在Windows 8 起, 其中一個新增的功能是Toast Notification. 而在Windows 10 中更加入了Notification Center令整個配套更齊備. 在此示範中, 會嘗試以WPF Application觸發Toast Notification. 並當user 處理彈出的toast 時, 會開啟這個網站.
- 建立一個WPF Application, 並命名為WPF.ToastNotification.
- 因為Windows 8 以下執行時會有機會出問題, 故限制可以平台的執行.
用notepad開啟WPF.ToastNotification.csproject, 於Global 的<PropertyGroup>加入以下XML:<TargetPlatformVersion>8.0</TargetPlatformVersion>
- 於Project 中加入Reference 指向WinMD.dll, 從而令project 可以叫用Window RT 的API call.
檔案位置: C:\Program Files (x86)\Windows Kits\8.0\References\CommonConfiguration\Neutral\Windows.winmd
- 開啟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>
- 於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時)觸發.
- 執行程式, 輸入內容, 並按下Send, 當Toast Message 出現及相對內容出現, 視為成功.
Reference
- WinRT Toast Notification From Desktop Application, Shai Raiten
- ToastNotificationManager class, MSDN
- Toast schema, MSDN
- ToastTemplateType enumeration, MSDN
Leave a Reply