I developed a .NET windows application which worked both on Windows 7 and 8.1. Then I added the Toast notification feature that came with Windows 8 (from this question: How can I use the Windows.UI namespace from a regular (Non-Store) Win32 .NET application? ). This also worked, I just had to add:
<PropertyGroup> <TargetPlatformVersion>8.0</TargetPlatformVersion> </PropertyGroup>
to the project file.
As I referenced the Windows.winmd file from the Windows 8.1 SDK C:\\Program Files (x86)\\Windows Kits\\8.1\\References\\CommonConfiguration\\Neutral\\Windows.winmd
, the executable does not start on Windows 7 anymore! I double-click and that's it. No errors, no messages.
As I did not find any solution online, that's where my question comes up: How do I manage to do both: Offer the toast feature to my users AND make the same .exe run on Windows 7 ?
Thank you in advance!
EDIT It turns out that though TargetPlatformVersion is set to 8.0, the executable starts on Windows 7 anyway, but crashes as soon as the program tries to load the Windows 8 libraries:
An unhandled exception of type 'System.TypeLoadException' occurred in ToastTester.exe. Additional information: Could not find Windows Runtime type 'Windows.UI.Notifications.ToastNotificationManager'.
on line Application.Run(new Form1());
In Form1.cs in line 9 I've got using Windows.UI.Notifications;
What is the best way to avoid this exception during runtime, even though it is expected that this executable will run in environments like Windows 7 where the Windows.UI.Notifications namespace is definitely not available?
I designed my own workaround for being able to support Windows 8 toasts and at the same time prevent application crashes due to missing libraries when running on Windows 7. Note: I am using the Singleton design pattern (member INSTANCE
), but you can always do it otherwise.
ShellLink.cs is taken from here
Win8Toaster.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace ToastManager
{
class Win8Toaster
{
public const string APPUSERMODELID = "YourCompany.YourApplicationName";
public static string ShortcutLocation;
public static ToastNotifier ToastNotifier;
private static Win8Toaster _INSTANCE = null;
public static Win8Toaster INSTANCE
{
get
{
if (_INSTANCE == null)
{
_INSTANCE = new Win8Toaster();
}
return _INSTANCE;
}
}
public Win8Toaster()
{
ShortcutLocation = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\Microsoft\Windows\Start Menu\Programs\YourCompany\YourApplication.lnk");
//We need a start menu shortcut (a ShellLink object) to show toasts.
if (!File.Exists(ShortcutLocation))
{
string directory = Path.GetDirectoryName(ShortcutLocation);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
using (ShellLink shortcut = new ShellLink())
{
shortcut.TargetPath = System.Reflection.Assembly.GetEntryAssembly().Location;
shortcut.Arguments = "";
shortcut.AppUserModelID = APPUSERMODELID;
shortcut.Save(ShortcutLocation);
}
}
ToastNotifier = ToastNotificationManager.CreateToastNotifier(APPUSERMODELID);
}
public void ShowToast(ToastContent Content)
{
XmlDocument ToastContent = new XmlDocument();
ToastContent.LoadXml("<toast><visual><binding template=\"ToastImageAndText02\"><image id=\"1\" src=\"file:///" + Content.ImagePath + "\"/><text id=\"1\">" + Content.Text1 + "</text><text id=\"2\">" + Content.Text2 + "</text></binding></visual></toast>");
ToastNotification thisToast = new ToastNotification(ToastContent);
ToastNotifier.Show(thisToast);
}
}
}
Toaster.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace ToastManager
{
public static class Toaster
{
private static Win8Toaster ActiveToaster;
public static bool Win8ToasterAvailable = true;
public static void ShowToast(ToastContent Content)
{
if (Win8ToasterAvailable)
{
if (ActiveToaster == null)
{
if (Environment.OSVersion.Version.Major > 6 || Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2)
{
try
{
ActiveToaster = Win8Toaster.INSTANCE;
}
catch (Exception ex)
{
Win8ToasterAvailable = false;
}
}
else
{
Win8ToasterAvailable = false;
}
}
ActiveToaster.ShowToast(Content);
}
else
{
//Use alternative notifications because Windows 8 Toasts are not available
}
}
}
//I also wrote my own toast content structure:
public class ToastContent
{
public string ImagePath, Text1, Text2;
public ToastContent(string ImagePath, string Text1, string Text2)
{
this.ImagePath = ImagePath;
this.Text1 = Text1;
this.Text2 = Text2;
}
}
}
Now that you've got the necessary classes, here is how to use it (pretty simple, huh?):
ToastManager.Toaster.ShowToast(new ToastManager.ToastContent(@"..\path\toyour\image.png", "Your Application Name", "Time: " + DateTime.Now.ToLongTimeString()));
This example shows a toast notification with the current system time or nothing if you are on Windows 7.
A design suggestion:
I used WinForms to design a notification window which looks similar to that in Windows 8 and simulates the same functions, just with my own forms. Alternatively you can also implement a tray icon and show some notification bubbles.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.