Partilhar via


How to create alarms and reminders for Windows Phone 8

[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]

Use the Alarm and Reminder classes, which inherit from ScheduledNotification, and the ScheduledActionService class to create and register scheduled notifications with the system. Alarms and Reminders are scheduled to be launched at a specified time in the future and can be configured to launch on a recurring schedule. When a reminder is launched, a dialog is launched that shows a title and additional text content that your app specifies. If the user taps the reminder UI, your app is launched and is navigated to a page that you specify. You can use query string parameters to pass information into your app when it is launched. When an alarm is launched, the title “Alarm” is always displayed along with additional text content you provide. Alarms also allow you to specify a custom sound file that is played when it is launched. If the user taps the Alarm UI, the app that created it is launched and the initial app page is shown.

This topic walks you all the way through creating an app that uses alarms and reminders. The usage of these two types of scheduled notifications is very similar. Only a small part of the code in this example is different for alarms and reminders. In the following steps, you will implement three app pages:

  1. Creating a Page to List Scheduled Notifications. This page displays a list of all alarms and reminders created and registered by the app. This page also allows you to delete notifications from the list.

  2. Creating a Page to Add Scheduled Notifications. This page uses controls to create an input form that allows the user to create new alarms and reminders.

  3. Creating a Reminder-Launched Page. This is the page to which the app will navigate if it is launched as a result of the user tapping a reminder dialog. This page will display data passed to the page on the query string. This functionality applies only to reminders. Alarms always launch the initial app page and do not pass query string parameters.

Creating a page to list scheduled notifications

The first page that you create in this example is a page that lists all of the alarms and reminders that are registered for your app. This example uses a ListBox control that is databound to an IEnumerable object containing the list of scheduled notifications. However, for the sake of simplicity, this example will not implement the full Model-View-ViewModel framework. For more information about this common Windows Phone app pattern, see Implementing the Model-View-ViewModel pattern for Windows Phone 8.

To create the reminder list page

  1. In Visual Studio, create a new Windows Phone app.

  2. The first step in creating the reminder list page is to create the user interface in XAML. Because the XAML code necessary to create a good-looking UI can be bulky, the XAML code is presented first and then the important elements are highlighted. For in-depth information about using controls, see Controls for Windows Phone 8.

    Paste the following code into the MainPage.xaml file in your project. The code should be pasted inside the Grid element that is named “ContentPanel”.

    <TextBlock Text="you have no notifications registered" Name="EmptyTextBlock" Visibility="Collapsed"/>
      <ListBox Name="NotificationListBox">
        <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>
    

    Look at the code you pasted and take note of the following elements:

    • The first TextBlock control is used to display a message to the user when there are no scheduled notifications to display. The C# code-behind page will toggle the Visibility property of this control to Visible when there are no items and the list and Collapsed when there are items in the list to be displayed.

    • The ListBox element defines the control that will list all of the scheduled notifications and their associated data. The rest of the XAML code doesn’t actually add items to the list. Instead, it contains a DataTemplate that tells the ListBox how to display the data that is bound to it. The ListBox name, “NotificationListBox”, is the name that will be used to reference the control in the C# code-behind page.

    • The Grid and StackPanel elements are container controls that are used to organize the layout of the other controls.

    • The TextBlock elements inside of the Grid and StackPanel controls display the values of the properties in the ScheduledNotification class. For example, the Content property is the text content of the alarm or reminder. The RecurrenceType property tells you on what interval the reminder will be launched. The syntax “{Binding RecurrenceType}” maps the Text property of each of these controls to the specified property name. Additional TextBlock controls are included to provide a label for each value. Note that the Alarm class does not support the Title property, so the control bound to this property will be empty for alarms.

    • Finally, a Button is added to allow the user to delete scheduled notifications. The Name property of the Alarm or Reminder is used to uniquely identify each notification. This value is bound to the Tag property of the Button so that the Click event handler for the button, deleteButton_Click, can determine which notification to delete. This handler will be added to the C# code-behind page later.

  3. The last thing you need to add to MainPage.xaml is an ApplicationBar. The ApplicationBar will have one ApplicationBarIconButton that the user can tap to go to the page that is used to add new scheduled notifications. Paste the following code over the commented-out example ApplicationBar code that is included in the template. Make sure that you replace the comments as well so that this code isn’t commented out.

    <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>
    
  4. Now it is time to modify the code in MainPage.xaml.cs. First, you need to add a using directive to include the namespace that contains the Reminder class. Add this line to the other using directives at the top of the file.

    using Microsoft.Phone.Scheduler;
    
  5. Next, add a class variable of type IEnumerable<ScheduledNotification>. The “<ScheduledNotification>” part of the variable type indicates that the IEnumerable object will contain ScheduledNotification objects. Add this code just below the MainPage class definition as shown.

    public partial class MainPage : PhoneApplicationPage
    {
      IEnumerable<ScheduledNotification> notifications;
    
  6. Create a method called ResetItemsList. This method will use the GetActions<(Of <(T>)>)()()() method to retrieve the ScheduledNotification objects that are registered with the ScheduledActionService for this app.

    If the list of scheduled notifications contains one or more items, the text block that informs the user that no notifications are registered is collapsed; otherwise, it is made visible. Finally, the ItemsSource property of the ListBox is set to the IEnumerable class variable containing the list of notifications. This forces the ListBox to update itself. Paste the following method definition inside the MainPage class definition.

    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>();
      notifications = ScheduledActionService.GetActions<ScheduledNotification>();
    
      // 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)
      if (notifications.Count<ScheduledNotification>() > 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.
      NotificationListBox.ItemsSource = notifications;
    }
    
  7. Override the OnNavigatedTo(NavigationEventArgs) method of the page’s PhoneApplicationPage base class. This class is called whenever the user navigates to the page, including when the app is launched and the page is first displayed. Whenever this event is raised, it will call the ResetItemsList method that was just defined.

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
      //Reset the ReminderListBox items when the page is navigated to.
      ResetItemsList();
    }
    
  8. Now implement the Click event handler for the delete buttons that were created in the XAML. There will be one delete button for each scheduled notification in the list, but all of these buttons will use the same handler. To determine which notification should be deleted, this method checks the Tag property and then calls the Remove(String) method of the ScheduledActionService. Remember, the Name property of a ScheduledNotification – and all other ScheduledAction types – uniquely identifies the objects for each app. After the item is deleted, ResetItemsList is called to update the UI.

    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();
    }
    
  9. The last update to MainPage.xaml.cs is to create the Click event handler for the ApplicationBarIconButton that the user taps to add a new alarm or reminder. The Navigate method is used to navigate the app to AddNotification.xaml which will be implemented in the next section.

    private void ApplicationBarAddButton_Click(object sender, EventArgs e)
    {
      // Navigate to the AddReminder page when the add button is clicked.
      NavigationService.Navigate(new Uri("/AddNotification.xaml", UriKind.RelativeOrAbsolute));
    }
    

Creating a page to add scheduled notifications

The next step in this walkthrough is to create a page that allows the user to add new alarms and reminders. This page must be able to allow the user to select the date and time at which the new alarm or reminder will be launched. Windows Phone SDK 7.1 does not provide a built-in control for performing this task, and creating a control from scratch is a large undertaking. For this reason, this example uses the DatePicker and TimePicker controls that are included in the Windows Phone Toolkit. You need to install the toolkit before the code presented here will compile. The following steps explain how to use the toolkit controls in your app.

To create a page to add scheduled notifications

  1. Install the Windows Phone Toolkit.

  2. From your computer’s Start menu, go to All Programs-> Windows Phone->Binaries. In the Windows Explorer window that is opened, copy Microsoft.Phone.Controls.Toolkit.dll and paste it into your app project directory. In Visual Studio, from the Project menu, select Add Reference…. Browse to your app project directory, select Microsoft.Phone.Controls.Toolkit.dll, and click OK.

  3. Add a new page to your project. From the Project menu, select Add New Item…. Select Windows Phone Portrait Page. In the Name text box, type AddNotification.xaml.

  4. In Solution Explorer, double-click AddNotification.xaml to open it. Add an XML namespace declaration to the root phone:PhoneApplicationPage element, next to the other namespace declarations.

    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
    
  5. Next, add the controls that allow the user to set the properties of the new alarm reminder. Paste the following code into AddNotification.xaml. The code should be pasted inside the Grid element that is named “ContentPanel”.

    <ScrollViewer>
      <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
          <RadioButton Content="Reminder" Name="reminderRadioButton" GroupName="ReminderOrAlarm" IsChecked="True"></RadioButton>
          <RadioButton Content="Alarm" Name="alarmRadioButton" GroupName="ReminderOrAlarm" ></RadioButton>
        </StackPanel>
        <TextBlock Height="30" HorizontalAlignment="Left"  Name="titleLabel" Text="title" VerticalAlignment="Top" />
        <TextBox Height="72" HorizontalAlignment="Left"  Name="titleTextBox" Text="" VerticalAlignment="Top" Width="460" MaxLength="63"/>
        <TextBlock Height="30" HorizontalAlignment="Left"  Name="contentLabel" Text="content" VerticalAlignment="Top" />
        <TextBox Height="160" HorizontalAlignment="Left"  Name="contentTextBox" Text="" VerticalAlignment="Top" Width="460" TextWrapping="Wrap" MaxLength="256" AcceptsReturn="True" />
        <TextBlock Height="30" HorizontalAlignment="Left"  Name="beginTimeLabel" Text="begin time" VerticalAlignment="Top" />
        <StackPanel Orientation="Horizontal">
          <toolkit:DatePicker x:Name="beginDatePicker" Width="220" HorizontalAlignment="Left"></toolkit:DatePicker>
          <toolkit:TimePicker x:Name="beginTimePicker"  Width="220" HorizontalAlignment="Right"></toolkit:TimePicker>
        </StackPanel>
        <TextBlock Height="30" HorizontalAlignment="Left"  Name="expirationTimeLabel" Text="expiration time" VerticalAlignment="Top" />
        <StackPanel Orientation="Horizontal">
          <toolkit:DatePicker x:Name="expirationDatePicker" Width="220" HorizontalAlignment="Left"></toolkit:DatePicker>
          <toolkit:TimePicker x:Name="expirationTimePicker" Width="220" HorizontalAlignment="Right"></toolkit:TimePicker>
        </StackPanel>
        <Grid>
          <RadioButton Content="once" Height="72" HorizontalAlignment="Left" Margin="0,0,0,0" Name="onceRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval" IsChecked="True"/>
          <RadioButton Content="weekly" Height="72" HorizontalAlignment="Left" Margin="0,70,0,0" Name="weeklyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/>
          <RadioButton Content="daily" Height="72" HorizontalAlignment="Left" Margin="0,140,0,0" Name="dailyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/>
          <RadioButton Content="monthly" Height="72" HorizontalAlignment="Left" Margin="240,0,0,0" Name="monthlyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/>
          <RadioButton Content="end of month" Height="72" HorizontalAlignment="Left" Margin="240,70,0,0" Name="endOfMonthRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/>
          <RadioButton Content="yearly" Height="72" HorizontalAlignment="Left" Margin="240,140,0,0" Name="yearlyRadioButton" VerticalAlignment="Top" GroupName="ScheduleInterval"/>
        </Grid>
        <TextBlock Height="30" HorizontalAlignment="Left" Name="param1Label" Text="context parameter 1" VerticalAlignment="Top" />
        <TextBox Height="72" HorizontalAlignment="Left" Name="param1TextBox" Text="" VerticalAlignment="Top" Width="440" MaxLength="63"/>
        <TextBlock Height="30" HorizontalAlignment="Left" Name="param2Label" Text="context parameter 2" VerticalAlignment="Top" />
        <TextBox Height="72" HorizontalAlignment="Left" Name="param2TextBox" Text="" VerticalAlignment="Top" Width="440" MaxLength="63"/>
    
      </StackPanel>
    </ScrollViewer>
    

    The XAML code in the previous section includes the following controls:

    • A pair of RadioButton controls to allow the user to switch between adding alarms and reminders.

    • TextBox controls for the Title and Content properties. The MaxLength property is set on these controls to restrict the input to the character limits of the properties. Note that the Alarm class does not support the Title property, so this value will not be used when creating alarms.

    • A DatePicker and TimePicker control for the BeginTime property. Together, these specify the time at which the notification will be first launched. These controls are from the Windows Phone Toolkit, which is why they use the toolkit namespace that was defined earlier.

    • A DatePicker and TimePicker control for the ExpirationTime property. This determines the time after which recurring notifications will no longer be launched.

    • RadioButtons to set the RecurrenceType property. This determines the interval between launches of the notification.

    • Two text boxes that allow the user to set two arbitrary parameter values that will be attached to the NavigationUri property. When a reminder is launched, and the user taps the reminder UI, the app will be launched, and the URI provided will be navigated to. This feature allows you to attach contextual information to the reminder. This functionality is not supported for alarms.

    • TextBlock controls are used throughout as labels for the other controls.

  6. Add an ApplicationBar to the XAML by pasting this code over the commented out ApplicationBar code. This provides the Save button that, when clicked, will attempt to create the new scheduled notification from the values in the UI and register it with the system.

    <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>
    
  7. Double-click AddNotification.xaml.cs in Solution Explorer to open it and add a using directive for the Scheduler namespace to the using directives at the top of the file.

    using Microsoft.Phone.Scheduler;
    
  8. All of the other code for this page will be placed in the Click event handler for the Save button. Paste this empty definition inside the AddNotification class definition.

    private void ApplicationBarSaveButton_Click(object sender, EventArgs e)
    {
      // The code in the following steps goes here.
    }
    
  9. Generate a unique name for the new notification. Your app can use any naming convention for notifications, but the name must be unique for each notification within an app. This example generates a GUID for each reminder name. Paste the following code inside the Save button Click handler.

      // Generate a unique name for the new notification. You can choose a
      // name that is meaningful for your app, or just use a GUID.
      String name = System.Guid.NewGuid().ToString();
    
  10. Combine the date and time values for the BeginTime property. Verify that the time is after the current time and, if it is not, alert the user and exit the Click handler. Then do the same for the ExpirationTime values. The expiration time must be after the begin time.

      // Get the begin time for the notification 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 notification.
      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;
      }
    
  11. Check to see which of the radio buttons is checked to determine the recurrence interval. The default value for this property is None.

      // 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;
      }
    
  12. Build a URI to set the NavigationUri property. The base of the URI is set to ShowParams.xaml, which will be created next. The values of the parameter text boxes are added to the URI as query string parameters. This value will only be used if a reminder is created.

      // 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 + "&param2=" + param2Value;
      }
      else if(param1Value != "" || param2Value != "")
      {
        queryString = (param1Value!=null) ? "?param1="+param1Value : "?param2="+param2Value;
      }
      Uri navigationUri = new Uri("/ShowParams.xaml" + queryString, UriKind.Relative);
    
  13. Check to see if the RadioButton for reminders is checked. If so, create a new reminder and set the properties that were just extracted from the UI. Use the Add(ScheduledAction) method of the ScheduledActionService class to register the new reminder with the system.

      if ((bool)reminderRadioButton.IsChecked)
      {
        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);
      }
    
  14. If the reminder RadioButton isn’t checked, then create an alarm. This works the same as adding a reminder except that the Title and NavigationUri properties aren’t supported. Also, an alarm allows you to specify Sound to play when the alarm is invoked. Add a sound file to your project by selecting Project->Add Existing Item… in Visual Studio. Once the sound has been added, make sure its Build Action property is set to Content.

      else
      {
        Alarm alarm = new Alarm(name);
        alarm.Content = contentTextBox.Text;
        alarm.Sound = new Uri("/Ringtones/Ring01.wma", UriKind.Relative);
        alarm.BeginTime = beginTime;
        alarm.ExpirationTime = expirationTime;
        alarm.RecurrenceType = recurrence;
    
        ScheduledActionService.Add(alarm);
      }
    
  15. Finally, call GoBack()()() to return the user to the reminder list page.

      // Navigate back to the main reminder list page.
     NavigationService.GoBack();
    

Creating a reminder-launched page

In the previous section, a page was created to add new alarms and reminders to the system. When a reminder is launched and the user taps it, the page specified in the NavigationUri property is launched. In this example, a page is created to simply display the query string parameters appended to the URI.

To create a schedule-launched page

  1. Add a new page to your project. From the Project menu, select Add New Item…. Select Windows Phone Portrait Page. In the Name text box, type ShowParams.xaml.

  2. Add TextBlock controls to ShowParams.xaml that will be used to show the query string parameters. The code should be pasted inside the Grid element that is named “ContentPanel”.

    <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}" />
    
  3. Override the OnNavigatedTo(NavigationEventArgs) method of the base PhoneApplicationPage class. This method will be called when the app is launched from a reminder, causing a navigation to this page. In this method, get the query string values using the NavigationContext class and set the Text property of the TextBlock objects to display the values.

    // 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;
    }