[WPF] 於Windows 10 叫用Toast Notification

在Windows 8 起, 其中一個新增的功能是Toast Notification. 而在Windows 10 中更加入了Notification Center令整個配套更齊備. 在此示範中, 會嘗試以WPF  Application觸發Toast Notification. 並當user 處理彈出的toast 時, 會開啟這個網站.

  1. 建立一個WPF Application, 並命名為WPF.ToastNotification.
  2. 因為Windows 8 以下執行時會有機會出問題, 故限制可以平台的執行.
    用notepad開啟WPF.ToastNotification.csproject, 於Global 的<PropertyGroup>加入以下XML:

    <TargetPlatformVersion>8.0</TargetPlatformVersion>

  3. 於Project 中加入Reference 指向WinMD.dll, 從而令project 可以叫用Window RT 的API call.
    檔案位置: C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd
  4. 開啟MainWindow.xaml, 並貼上以下的code.
    <Window x:Class="WPF.ToastNotification.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WPF.ToastNotification"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto" />
                <RowDefinition Height="auto" />
                <RowDefinition Height="*" />
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" Grid.Column="0">
                <TextBlock Text="Title" />
                <TextBox Name="txtTitle" />
            </StackPanel>
            <StackPanel Grid.Row="1" Grid.Column="0">
                <TextBlock Text="Icon" />
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="auto" />
                    </Grid.ColumnDefinitions>
                    <TextBox Grid.Column="0" Name="txtIconPath" IsReadOnly="True" />
                    <Button Grid.Column="1" Name="btnIconPath" Click="btnIconPath_Click">Browse...</Button>
                </Grid>
            </StackPanel>
            <DockPanel Grid.Row="2" Grid.Column="0">
                <TextBlock Text="Content" DockPanel.Dock="Top" />
                <TextBox Name="txtContent" TextWrapping="Wrap" AcceptsReturn="True"  />
            </DockPanel>
            <StackPanel Grid.Row="3" Grid.Column="0">
                <Button Name="btnSend" Click="btnSend_Click">Send</Button>
            </StackPanel>
        </Grid>
    </Window>
    
  5. 於code-behide 的MainWindow.xaml.cs, 加入以下內容.
    using System;
    using System.Diagnostics;
    using System.Windows;
    using Windows.Data.Xml.Dom;
    using Windows.UI.Notifications;
    
    namespace WPF.ToastNotification
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private const string APP_ID = "WPF ToastNotificaiton Test";
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
    
            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(txtContent.Text));
    
                String imagePath = txtIconPath.Text;
    
                XmlNodeList imageElements = toastXml.GetElementsByTagName("image");
                imageElements[0].Attributes.GetNamedItem("src").NodeValue = imagePath;
    
                Windows.UI.Notifications.ToastNotification toast = new Windows.UI.Notifications.ToastNotification(toastXml);
                toast.Activated += toast_Activated;
                toast.Dismissed += toast_Dismissed;
                toast.Failed += toast_Failed;
    
                // You must specifiy AppUserModelId == APP_ID to send toast notification.
                ToastNotificationManager.CreateToastNotifier(APP_ID).Show(toast);
    
                //lblStatus.Text = "Toast Sent!";
            }
    
            private void btnIconPath_Click(object sender, RoutedEventArgs e)
            {
                // Create OpenFileDialog 
                Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
    
                // Set filter for file extension and default file extension 
                dlg.DefaultExt = ".png";
                dlg.Filter = "JPEG Files (*.jpeg)|*.jpeg|PNG Files (*.png)|*.png|JPG Files (*.jpg)|*.jpg|GIF Files (*.gif)|*.gif";
    
                // Display OpenFileDialog by calling ShowDialog method 
                Nullable<bool> result = dlg.ShowDialog();
    
                // Get the selected file name and display in a TextBox 
                if (result == true)
                {
                    // Open document 
                    string filename = dlg.FileName;
                    txtIconPath.Text = filename;
                }
            }
    
            private void toast_Failed(Windows.UI.Notifications.ToastNotification sender, ToastFailedEventArgs args)
            {
                Dispatcher.Invoke(() =>
                {
                   MessageBox.Show(string.Format("Toast Failed - Error Code: {0}", args.ErrorCode.Message));
                });
            }
    
            private void toast_Dismissed(Windows.UI.Notifications.ToastNotification sender, ToastDismissedEventArgs args)
            {
                Dispatcher.Invoke(() =>
                {
                    MessageBox.Show(args.Reason.ToString());
                });
            }
    
            private void toast_Activated(Windows.UI.Notifications.ToastNotification sender, object args)
            {
                Dispatcher.Invoke(() =>
                {
                    Activate();
                    Process.Start("https://www.chunho-ling.com");
                });
            }
        }
    }
    

    在以上的code中, 可以留意:

    • ToastTemplateType: 決定Template 的Layout, 詳細可以參考ToastTemplateType enumeration;
    • Toast 的layout 其實以XML作基準, 詳細可參考Toast schema;
    • 而應對user behaviour有幾個event:
       事件 描述 
      toast.Activated 當user 按下Toast時觸發. 
      toast.Dismissed 當Toast 消失時觸發. 
      toast_Failed 當Toast 不能正常popup(例如user disable時)觸發. 
  6. 執行程式, 輸入內容, 並按下Send, 當Toast Message 出現及相對內容出現, 視為成功.

     

Reference

About C.H. Ling 262 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.