修炼九阴真经Windows Phone开发 (9):计划通知Reminder和Alarm
应用程序可以使用预定操作执行任务,即使在主应用程序未在前台运行。此功能的两个子类:计划通知(包括提醒和警告)和计划任务(定期的资源密集型任务在后台执行)。
WP 的计划通知功能允许应用程序创建有关警告和提醒的可配置的计划表;计划任务功能允许注册后台代理去执行计划的任务。
一、计划通知
计划通知在预定的时间,在手机屏幕中弹出信息提醒和警告的对话框,类似于windows phone 内置的通知。对话框的内容为自定义的文本信息,并允许用户取消和推迟通知。
如果用户点击通知,与通知相关联的应用程序将启动。计划通知可以配置为启动一次或多次重复执行的计划,请注意计划知道的时间表精确到分。
计划通知有两种类型:警告(Alarm) 和提醒(Reminder)。报警允许指定通知程序启动时播放的语音文件;提醒则声明与通知相关联的URI指向应用程序中的页面,包括查询
字符串参数。用户点击提醒后,与此通知相关的应用程序将启动并显示声明的URL页面。
二、计划任务
计划任务允许应用程序执行后台代理程序,执行条件是主程序未激活。与计划通知不同的是,计划任务只能选择两种类型执行,即 PeriodicTask 和 ResourceIntensiveTask.
PeriodicTask 定期执行,但是执行时间短,且限制使用处理周期和内存等系统资源。此类型适合快速任务,比如检查启用位置功能的WEB服务的用户数,或者缓冲小量数据。
ResourceIntensiveTask 不定期执行,在设备处于资源充沛的情况下执行,比如设备处于WIFI网络连接状态并且设备采用外接电源供电。此类型的任务在允许使用充足的设备资源时,可以运行更长的时间处理大量的数据,即此类型的任务执行时间是弹性的。
示例(定时通知闹钟)
主界面:
<phone:PhoneApplicationPage x:Class="ReminderSample.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="REMINDER APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="reminders" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Text="you have no reminders registered" Name="EmptyTextBlock" Visibility="Collapsed"/> <ListBox Name="ReminderListBox"> <ListBox.ItemTemplate> <DataTemplate> <Grid Background="Transparent" Margin="0,0,0,30"> <Grid.ColumnDefinitions> <ColumnDefinition Width="380"/> <ColumnDefinition Width="50"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Title}" TextWrapping="NoWrap" Foreground="{StaticResource PhoneAccentBrush}" FontWeight="Bold"/> <TextBlock Text="{Binding Content}" TextWrapping="Wrap" Foreground="{StaticResource PhoneAccentBrush}"/> <StackPanel Orientation="Horizontal"> <TextBlock Text="begin "/> <TextBlock Text="{Binding BeginTime}" HorizontalAlignment="Right"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="expiration "/> <TextBlock Text="{Binding ExpirationTime}" HorizontalAlignment="Right"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="recurrence "/> <TextBlock Text="{Binding RecurrenceType}" HorizontalAlignment="Right"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="is scheduled? "/> <TextBlock Text="{Binding IsScheduled}" HorizontalAlignment="Right"/> </StackPanel> </StackPanel> </Grid> <Grid Grid.Column="1"> <Button Tag="{Binding Name}" Click="deleteButton_Click" Content="X" BorderBrush="Red" Background="Red" Foreground="{StaticResource PhoneBackgroundBrush}" VerticalAlignment="Top" BorderThickness="0" Width="50" Padding="0,0,0,0"></Button> </Grid> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Grid> <!--Sample code showing usage of ApplicationBar--> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton IconUri="/Images/add.png" Text="Add" Click="ApplicationBarAddButton_Click"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> </phone:PhoneApplicationPage>
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Phone.Scheduler; namespace ReminderSample { public partial class MainPage : PhoneApplicationPage { IEnumerable<Reminder> reminders; // Constructor public MainPage() { InitializeComponent(); } private void ResetItemsList() { // Use GetActions to retrieve all of the scheduled actions // stored for this application. The type <Reminder> is specified // to retrieve only Reminder objects. reminders = ScheduledActionService.GetActions<Reminder>(); // If there are 1 or more reminders, hide the "no reminders" // TextBlock. IF there are zero reminders, show the TextBlock. if (reminders.Count<Reminder>() > 0) { EmptyTextBlock.Visibility = Visibility.Collapsed; } else { EmptyTextBlock.Visibility = Visibility.Visible; } // Update the ReminderListBox with the list of reminders. // A full MVVM implementation can automate this step. ReminderListBox.ItemsSource = reminders; } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); // Reset the ReminderListBox items when the page is navigated to. ResetItemsList(); } private void deleteButton_Click(object sender, RoutedEventArgs e) { // The scheduled action name is stored in the Tag property // of the delete button for each reminder. string name = (string)((Button)sender).Tag; // Call Remove to unregister the scheduled action with the service. ScheduledActionService.Remove(name); // Reset the ReminderListBox items ResetItemsList(); } private void ApplicationBarAddButton_Click(object sender, EventArgs e) { // Navigate to the AddReminder page when the add button is clicked. NavigationService.Navigate(new Uri("/AddReminder.xaml", UriKind.RelativeOrAbsolute)); } } }
设置界面:
<phone:PhoneApplicationPage x:Class="ReminderSample.AddReminder" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="REMINDER APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="add reminder" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <ScrollViewer> <Grid> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,10,0,0" Name="titleLabel" Text="title" VerticalAlignment="Top" /> <TextBox Height="72" HorizontalAlignment="Left" Margin="0,30,0,0" Name="titleTextBox" Text="" VerticalAlignment="Top" Width="460" MaxLength="63"/> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,100,0,0" Name="contentLabel" Text="content" VerticalAlignment="Top" /> <TextBox Height="160" HorizontalAlignment="Left" Margin="0,120,0,0" Name="contentTextBox" Text="" VerticalAlignment="Top" Width="460" TextWrapping="Wrap" MaxLength="256" AcceptsReturn="True" /> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,280,0,0" Name="beginTimeLabel" Text="begin time" VerticalAlignment="Top" /> <toolkit:DatePicker x:Name="beginDatePicker" Margin="0,300,0,0" Width="220" HorizontalAlignment="Left"></toolkit:DatePicker> <toolkit:TimePicker x:Name="beginTimePicker" Margin="0,300,0,0" Width="220" HorizontalAlignment="Right"></toolkit:TimePicker> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,370,0,0" Name="expirationTimeLabel" Text="expiration time" VerticalAlignment="Top" /> <toolkit:DatePicker x:Name="expirationDatePicker" Margin="0,390,0,0" Width="220" HorizontalAlignment="Left"></toolkit:DatePicker> <toolkit:TimePicker x:Name="expirationTimePicker" Margin="0,390,0,0" Width="220" HorizontalAlignment="Right"></toolkit:TimePicker> <RadioButton Content="once" Height="72" HorizontalAlignment="Left" Margin="12,470,0,0" Name="onceRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval" IsChecked="True"/> <RadioButton Content="weekly" Height="72" HorizontalAlignment="Left" Margin="211,470,0,0" Name="weeklyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/> <RadioButton Content="daily" Height="72" HorizontalAlignment="Left" Margin="9,540,0,0" Name="dailyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/> <RadioButton Content="monthly" Height="72" HorizontalAlignment="Left" Margin="211,540,0,0" Name="monthlyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/> <RadioButton Content="end of month" Height="72" HorizontalAlignment="Left" Margin="9,610,0,0" Name="endOfMonthRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/> <RadioButton Content="yearly" Height="72" HorizontalAlignment="Left" Margin="211,610,0,0" Name="yearlyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,690,0,0" Name="param1Label" Text="context parameter 1" VerticalAlignment="Top" /> <TextBox Height="72" HorizontalAlignment="Left" Margin="0,710,0,0" Name="param1TextBox" Text="" VerticalAlignment="Top" Width="460" MaxLength="63"/> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,780,0,0" Name="param2Label" Text="context parameter 2" VerticalAlignment="Top" /> <TextBox Height="72" HorizontalAlignment="Left" Margin="0,800,0,0" Name="param2TextBox" Text="" VerticalAlignment="Top" Width="460" MaxLength="63"/> </Grid> </ScrollViewer> </Grid> </Grid> <!--Sample code showing usage of ApplicationBar--> <phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton IconUri="/Images/save.png" Text="Save" Click="ApplicationBarSaveButton_Click"/> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar> </phone:PhoneApplicationPage>
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; using Microsoft.Phone.Scheduler; namespace ReminderSample { public partial class AddReminder : PhoneApplicationPage { public AddReminder() { InitializeComponent(); } private void ApplicationBarSaveButton_Click(object sender, EventArgs e) { // Generate a unique name for the new reminder. You can choose a // name that is meaningful for your app, or just use a GUID. String name = System.Guid.NewGuid().ToString(); // Get the begin time for the reminder by combining the DatePicker // value and the TimePicker value. DateTime date = (DateTime)beginDatePicker.Value; DateTime time = (DateTime)beginTimePicker.Value; DateTime beginTime = date + time.TimeOfDay; // Make sure that the begin time has not already passed. if (beginTime < DateTime.Now) { MessageBox.Show("the begin date must be in the future."); return; } // Get the expiration time for the reminder date = (DateTime)expirationDatePicker.Value; time = (DateTime)expirationTimePicker.Value; DateTime expirationTime = date + time.TimeOfDay; // Make sure that the expiration time is after the begin time. if (expirationTime < beginTime) { MessageBox.Show("expiration time must be after the begin time."); return; } // Determine which recurrence radio button is checked. RecurrenceInterval recurrence = RecurrenceInterval.None; if (dailyRadioButton.IsChecked == true) { recurrence = RecurrenceInterval.Daily; } else if (weeklyRadioButton.IsChecked == true) { recurrence = RecurrenceInterval.Weekly; } else if (monthlyRadioButton.IsChecked == true) { recurrence = RecurrenceInterval.Monthly; } else if (endOfMonthRadioButton.IsChecked == true) { recurrence = RecurrenceInterval.EndOfMonth; } else if (yearlyRadioButton.IsChecked == true) { recurrence = RecurrenceInterval.Yearly; } // Create a Uri for the page that will be launched if the user // taps on the reminder. Use query string parameters to pass // content to the page that is launched. string param1Value = param1TextBox.Text; string param2Value = param2TextBox.Text; string queryString = ""; if (param1Value != "" && param2Value != "") { queryString = "?param1=" + param1Value + "¶m2=" + param2Value; } else if(param1Value != "" || param2Value != "") { queryString = (param1Value!=null) ? "?param1="+param1Value : "?param2="+param2Value; } Uri navigationUri = new Uri("/ShowParams.xaml" + queryString, UriKind.Relative); Reminder reminder = new Reminder(name); reminder.Title = titleTextBox.Text; reminder.Content = contentTextBox.Text; reminder.BeginTime = beginTime; reminder.ExpirationTime = expirationTime; reminder.RecurrenceType = recurrence; reminder.NavigationUri = navigationUri; // Register the reminder with the system. ScheduledActionService.Add(reminder); // Navigate back to the main reminder list page. NavigationService.GoBack(); } } }
设置好的界面:
点击后能接受参数
<phone:PhoneApplicationPage x:Class="ReminderSample.ShowParams" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480" shell:SystemTray.IsVisible="True"> <!--LayoutRoot is the root grid where all page content is placed--> <Grid x:Name="LayoutRoot" Background="Transparent"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <!--TitlePanel contains the name of the application and page title--> <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> <TextBlock x:Name="ApplicationTitle" Text="REMINDER APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> <TextBlock x:Name="PageTitle" Text="show params" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> </StackPanel> <!--ContentPanel - place additional content here--> <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,10,0,0" Name="param1Label" Text="param1 value:" VerticalAlignment="Top" Foreground="{StaticResource PhoneForegroundBrush}" /> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,40,0,0" Name="param1TextBlock" Text="TextBlock" VerticalAlignment="Top" Foreground="{StaticResource PhoneAccentBrush}"/> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,80,0,0" Name="param2Label" Text="param2 value:" VerticalAlignment="Top" Foreground="{StaticResource PhoneForegroundBrush}"/> <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,110,0,0" Name="param2TextBlock" Text="TextBlock" VerticalAlignment="Top" Foreground="{StaticResource PhoneAccentBrush}" /> </Grid> </Grid> <!--Sample code showing usage of ApplicationBar--> <!--<phone:PhoneApplicationPage.ApplicationBar> <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"> <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/> <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/> <shell:ApplicationBar.MenuItems> <shell:ApplicationBarMenuItem Text="MenuItem 1"/> <shell:ApplicationBarMenuItem Text="MenuItem 2"/> </shell:ApplicationBar.MenuItems> </shell:ApplicationBar> </phone:PhoneApplicationPage.ApplicationBar>--> </phone:PhoneApplicationPage>
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Microsoft.Phone.Controls; namespace ReminderSample { public partial class ShowParams : PhoneApplicationPage { public ShowParams() { InitializeComponent(); } // Implement the OnNavigatedTo method and use NavigationContext.QueryString // to get the parameter values passed by the reminder. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); string param1Value = ""; string param2Value = ""; NavigationContext.QueryString.TryGetValue("param1", out param1Value); NavigationContext.QueryString.TryGetValue("param2", out param2Value); param1TextBlock.Text = param1Value; param2TextBlock.Text = param2Value; } } }