WinRT Toast Notification From Desktop Application

30/01/2013

The post title maintained Toast Notification but after reading this post we’ll be able to perform API calls to WinRT from your Desktop application.

As you know WinRT exposing API’s for three developer languages: C#, C++ and JavaScript, this means that from each language you’ll be able to perform WinRT calls. The idea is based on Windows Metadata File (winmd) that expose those APIs that can be consumed across a variety of technologies and languages.

image

Download Demo Project

So why not using those calls from a desktop application? for example one of the great features of Windows 8 is Toast Notifications, Toast is a super cool replacement for Message box dialog that block your screen and can be very enjoying…

A toast notification is a transient message to the user that contains relevant, time-sensitive information and provides quick access to related content in an app. It can appear whether you are in another app, the Start screen, the lock screen, or on the desktop. Toasts should be viewed as an invitation to return to your app to follow up on something of interest. Toast notifications are an optional part of the app experience and are intended to be raised only when your app is not the active foreground app.

let’s say that we want to send Toast from your Desktop application instead of displaying annoying message boxes, let’s see how you can do it.

Step 1: Getting Started With Windows.winmd

Let’s start with empty WPF application, let’s try to load Windows.winmd file located here:

C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd

You’ll receive below error message saying this file isn’t compatible with your current project.

image

You need to edit your csproj file and add TargetPlatformVersion element.

image

Locate the PropertyGroup and add additional element : <TargetPlatformVersion>8.0</TargetPlatformVersion>

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>{20DAA4E0-DE45-4FB6-8650-44FFDBA78F25}</ProjectGuid>
    <OutputType>WinExe</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>DesktopAppNotificationDemo</RootNamespace>
    <AssemblyName>DesktopAppNotificationDemo</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <TargetPlatformVersion>8.0</TargetPlatformVersion>
    <FileAlignment>512</FileAlignment>
    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <WarningLevel>4</WarningLevel>
    <PublishUrl>publish\</PublishUrl>

Now if you try to load Windows.winmd you’ll success, using the Object Browser you can explore the different API’s available in WinRT.

image

Step 2: API Code Pack

In order to display toasts, a desktop application must have a shortcut on the Start menu. Also, an AppUserModelID must be set on that shortcut.

The shortcut should be created as part of the installer. The following code shows how to create a shortcut and assign an AppUserModelID using Windows APIs.

You must download and include the Windows® API Code Pack for Microsoft® .NET Framework to allow Toast Notification from desktop application.

Windows® API Code Pack for Microsoft® .NET Framework provides a source code library that can be used to access some features of Windows 7 and Windows Vista from managed code. These Windows features are not available to developers today in the .NET Framework.

First thing after the application is loaded you need to make sure the application has a shortcut under Start menu referring to your desktop AppUserModelID.

private const String APP_ID = "Shai Raiten - DesktopAppNotificationDemo";
private bool IsAppLinkExists()
{
    string defaultPath = string.Format(@"{0}\Microsoft\Windows\Start Menu\Programs\{1}.lnk",
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        APP_ID);

    return File.Exists(defaultPath) == false ? CreateApplicationShortcut(defaultPath) : true;
}

In case there is no shortcut you’ll need to create one:

private bool CreateApplicationShortcut(string defaultPath)
{
    string exePath = Process.GetCurrentProcess().MainModule.FileName;
    var newShortcut = (IShellLinkW)new CShellLink();

    // Create a shortcut to the exe
    ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetPath(exePath));
    ShellHelpers.ErrorHelper.VerifySucceeded(newShortcut.SetArguments(""));

    // Open the shortcut property store, set the AppUserModelId property
    var newShortcutProperties = (IPropertyStore)newShortcut;

    using (PropVariant appId = new PropVariant(APP_ID))
    {
        ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.SetValue(SystemProperties.System.AppUserModel.ID, appId));
        ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutProperties.Commit());
    }

    // Commit the shortcut to disk
    var newShortcutSave = (IPersistFile)newShortcut;

    ShellHelpers.ErrorHelper.VerifySucceeded(newShortcutSave.Save(defaultPath, true));
    return true;
}

Step 3: Toast

If you not familiar with Toast under Windows 8 I’ll recommend you to read about the methods and events of ToastNotification class (Windows).

After completing all previous steps creating Toast is a simple task, all you need to do is create new Toast template using ToastNotificationManager and modify the Toast template xml with your data.

private void btnSend_Click(object sender, RoutedEventArgs e)
{
    var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastImageAndText02);

    var textFields = toastXml.GetElementsByTagName("text");
    textFields[0].AppendChild(toastXml.CreateTextNode(txtTitle.Text));
    textFields[1].AppendChild(toastXml.CreateTextNode(txtDescription.Text));

    String imagePath = "file:///" + System.IO.Path.GetFullPath("me.png");
    XmlNodeList imageElements = toastXml.GetElementsByTagName("image");
    imageElements[0].Attributes.GetNamedItem("src").NodeValue = imagePath;

    ToastNotification toast = new ToastNotification(toastXml);

    if (cal.SelectedDate != null)
        toast.ExpirationTime = cal.SelectedDate;

    // You must specifiy AppUserModelId == APP_ID to send toast notification.
    ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast);

    lblStatus.Text = "Toast Sent!";
}

image

Step 4: Toast Events

Toast as we already understand is more than just a MessageBox, you’ll be able to send information to your users and get their response, for example in this demo if the user click on the Toast I’ll like to open the browser to that specific Uri.

All you need to do is register to the Toast events before sending the toast.

toast.Activated += toast_Activated;
toast.Dismissed += toast_Dismissed;
toast.Failed += toast_Failed;
void toast_Failed(ToastNotification sender, ToastFailedEventArgs args)
{
    Dispatcher.Invoke(() =>
    {
        lblStatus.Text = string.Format("Toast Failed - Error Code: {0}", args.ErrorCode.Message);
    });
}

void toast_Dismissed(ToastNotification sender, ToastDismissedEventArgs args)
{
    Dispatcher.Invoke(() =>
    {
        lblStatus.Text = args.Reason.ToString();
    });
}

void toast_Activated(ToastNotification sender, object args)
{
    Dispatcher.Invoke(() =>
    {
        Activate();
        lblStatus.Text = "Toast Activated";
        Process.Start("http://tinyurl.com/shai-rai");
    });
}

Take Notice – You can use more WinRT API’s by adding Windows.winmd to your desktop application.

Download Demo Project

Enjoy

Add comment
facebook linkedin twitter email

Leave a Reply