Разработка под Windows Phone: Alarms и Reminders
Так ли нужна одновременная работа нескольких приложений в фоновом режиме? На самом деле, в большинстве случаев, нам нужно, чтобы приложение имело возможность оповестить пользователя о том, что что-то изменилось или необходимы какие-то действия с его стороны. И в этой части серии статей мы познакомимся с возможностями системы, которые позволяют нам оповещать пользователя, напоминать ему или даже предоставлять саму востребованную информацию без необходимости запускать приложение!
Предупреждения (Alarm) и напоминания (Reminder)
Приложения в Windows Phone могут использовать оповещения двух типов: предупреждения (Alarms) и напоминания (Reminders), которые будут отображаться пользователю в виде диалоговых окон, по расписанию. Интерфейс оповещений и напоминаний соответствует тому, который используют системные приложения. Это позволяет сторонним приложениям общаться с пользователем на знакомом ему языке системного интерфейса.
Объекты Alarm и Reminder наследуются от класса ScheduledNotification и имеют достаточно много общего, однако, есть и определенный отличия. Классический вариант оповещения Alarm – это будильник, а оповещения Reminder – напоминание о событии в календаре.
Обратите внимание, что каждое приложение может зарегистрировать до 50 оповещений, а точность отображения пользователю – около минуты.
Давайте кратко рассмотрим основные параметры оповещений.
Предупреждения (Alarm)
Предупреждение (Alarm) отображается пользователю в виде диалогового окна с 2-мя кнопками отложить (snooze) и закрыть (dismiss), а также тремя текстовыми блоками. Верхний блок – название приложения, которое зарегистрировало предупреждение. Далее, текстовый блок, который отображается всегда и не может быть изменён с надписью Будильник (Alarm) и, самый последний блок – текст, который был указан при создании предупреждения.
Предупреждение (Alarm) позволяет указать звуковой файл, который будет проигран при отображении его пользователю, он проигрывается с нарастающей громкостью.
Если пользователь коснётся любой области оповещения, кроме кнопок, будет загружено основное приложение и отобразится его начальная страница, так, как будто пользователь запустил его из списка программ.
Напоминание (Reminder)
Напоминание (Reminder) отображается пользователю в виде диалогового окна с 2-мя кнопками, выпадающим списком для выбора, на сколько отложить оповещение и тремя текстовыми блоками.
Верхний блок – название приложения, которое зарегистрировало предупреждение. Далее, текстовый блок, который отображает заголовок оповещения, который был указан при его создании, и, самый последний блок – текст – содержание напоминания, указанный при создании.
Если пользователь коснётся любой области оповещения, кроме кнопок, будет загружено основное приложение, при этом, разработчик, при создании напоминания может указать URI страницы с параметрами, на которые перейдёт пользователь.
В отличие от предупреждения (Alarm) будет вегда использоваться звук для оповещения установленный в настройках устройства.
Пример работы с Alarm и Reminder
Давайте теперь на практике попробуем разобраться с оповещениями.
Создадим новое приложение на базе стандартного шаблона Windows Phone Application и назовём приложение SimpleNotificationManager.
После того, как проект приложения будет создан, добавьте в приложение поддержку Silverlight for Windows Phone Toolkit.
Убедитесь, что у вас установлен NuGet Package Manager (Tools -> Extension Manager …)
При необходимости – установите.
После этого в меню Visual Studio выберите, Tools -> Library Package Manager -> Manage NuGet Packages …
Откроется графическая утилита установки пактов NuGet. Найдите и установите пакет Silverlight for Windows Phone Toolkit.
После этого, ваш проект будет выглядеть следующим образом.
Перед тем, как продолжить, для всех картинок в папке Toolkit.Content установите тип сборки (Build Action) в Content (по умолчанию стоит Resource).
Итак, Silverlight for Windows Phone Toolkit подключён к проекту. Давайте добавим, как мы это уже делали ранее, пространство имён toolkit в XAML файл MainPage.xaml, чтобы использовать элементы управления из Silverlight for Windows Phone Toolkit на нашей главной странице:
Мы добавили следующую строку:
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
И в результате XAML будет выглядеть следующим образом:
<phone:PhoneApplicationPage
x:Class="SimpleNotificationManager.MainPage"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
Теперь нужно сделать интерфейс создания оповещений. Нужен выбор типа, выбор времени оповещения, заголовка (в случае напоминания) и содержания. Я сделал простой интерфейс на базе комбинации элементов управления StackPanel:
При этом, XAML код страницы MainPage.xaml (внутри тега phone:PhoneApplicationPage) выглядит следующим образом:
<!--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="МЕНЕДЖЕР ОПОВЕЩЕН�Й"
Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="установка" 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">
<StackPanel>
<RadioButton Content="предупреждение" GroupName="NotificationType"
Name="AlarmType" IsChecked="True" />
<RadioButton Content="напоминание" GroupName="NotificationType"
Name="ReminderType" />
<StackPanel Orientation="Horizontal" Margin="15,0,0,0">
<TextBlock Text="дата и время" FontSize="22.667"
VerticalAlignment="Center"/>
<toolkit:DatePicker Name="NotificationDate"/>
<toolkit:TimePicker Name="NotificationTime"/>
</StackPanel>
<StackPanel Margin="15,15,0,0">
<TextBlock Name="NotificationTitleCaption" Text="заголовок оповещения"
FontSize="22.667" VerticalAlignment="Center" Visibility="Collapsed"/>
<TextBox Name="NotificationTitle" FontSize="22.667"
Margin="-10,0,0,0" Visibility="Collapsed"/>
<TextBlock Text="текст оповещения" FontSize="22.667"
VerticalAlignment="Center"/>
<TextBox Name="NotificationText" FontSize="22.667" Margin="-10,0,0,0"/>
</StackPanel>
<Button Content="установить" Name="SetNotification" FontSize="22.667" Width="450"/>
<Button Content="посмотреть список" Name="CheckNotification" FontSize="22.667" Width="450" />
</StackPanel>
</Grid>
</Grid>
В зависимости от того, какой тип оповещения создаётся, поле ввода для заголовка оповещения и соответствующий текстовый блок с названием поля либо отображаются, либо нет. По умолчанию, выбрано предупреждение и эти элементы управления не отображаются. Нам необходимо обрабатывать изменения типа создаваемого оповещения и либо отображать, либо не отображать этот блок.
Если мы назначим обработчики изменения состояний радио-кнопок в XAML коде, может сложиться такая ситуация, что они сработают ещё до того, как создадутся элементы управления, которые мы хотим скрывать/показывать. Поэтому, мы добавим в код обработчик события Loaded страницы, а уже в него добавим регистрацию обработчиков изменения состояния радио-кнопок:
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
AlarmType.Checked +=new RoutedEventHandler(AlarmType_Checked);
ReminderType.Checked +=new RoutedEventHandler(ReminderType_Checked);
}
И напишем обработчики событий радио-кнопок:
private void AlarmType_Checked(object sender, RoutedEventArgs e)
{
NotificationTitleCaption.Visibility = System.Windows.Visibility.Collapsed;
NotificationTitle.Visibility = System.Windows.Visibility.Collapsed;
}
private void ReminderType_Checked(object sender, RoutedEventArgs e)
{
NotificationTitleCaption.Visibility = System.Windows.Visibility.Visible;
NotificationTitle.Visibility = System.Windows.Visibility.Visible;
}
Теперь осталось добавим код, который собственно и создаёт предупреждения и напоминания.
Для упрощения кода, разрешим нашему приложению в каждый момент времени иметь только одно предупреждение и одно напоминание. Зададим для них имена (должны быть уникальными среди всех, создаваемых приложением оповещений) в виде констант в классе:
const string MY_ALARM = "My Alarm";
const string MY_REMINDER = "My Reminder";
Обратите внимание, что для использования объектов Alarm и Reminder необходимо добавить следующую запись в блок using:
using Microsoft.Phone.Scheduler;
Теперь напишем две простые функции, которые будут создавать Alarm и Reminder соответственно.
private void CreateAlarm()
{
DateTime date = (DateTime)NotificationDate.Value;
DateTime time = (DateTime)NotificationTime.Value;
DateTime beginTime = date + time.TimeOfDay;
if (beginTime < DateTime.Now)
{
MessageBox.Show("Указанное время оповещения уже прошло!");
return;
}
if (ScheduledActionService.Find(MY_ALARM) != null)
ScheduledActionService.Remove(MY_ALARM);
Alarm myAlarm = new Alarm(MY_ALARM);
myAlarm.Content = NotificationText.Text;
myAlarm.RecurrenceType = RecurrenceInterval.None;
myAlarm.BeginTime = beginTime;
myAlarm.ExpirationTime = beginTime.AddMinutes(5);
ScheduledActionService.Add(myAlarm);
}
private void CreateReminder()
{
DateTime date = (DateTime)NotificationDate.Value;
DateTime time = (DateTime)NotificationTime.Value;
DateTime beginTime = date + time.TimeOfDay;
if (beginTime < DateTime.Now)
{
MessageBox.Show("Указанное время оповещения уже прошло!");
return;
}
if (ScheduledActionService.Find(MY_REMINDER) != null)
ScheduledActionService.Remove(MY_REMINDER);
Reminder myReminder = new Reminder(MY_REMINDER);
myReminder.Title = NotificationTitle.Text;
myReminder.Content = NotificationText.Text;
myReminder.RecurrenceType = RecurrenceInterval.None;
myReminder.BeginTime = beginTime;
myReminder.ExpirationTime = beginTime.AddMinutes(5);
myReminder.NavigationUri = new Uri("/NotificationList.xaml",UriKind.RelativeOrAbsolute);
ScheduledActionService.Add(myReminder);
}
Давайте взглянем на код функций поближе.
Перед созданием мы выполняем простую проверку, что время, на которые мы хотим назначить оповещение еще не прошло:
DateTime date = (DateTime)NotificationDate.Value;
DateTime time = (DateTime)NotificationTime.Value;
DateTime beginTime = date + time.TimeOfDay;
if (beginTime < DateTime.Now)
{
MessageBox.Show("Указанное время оповещения уже прошло!");
return;
}
Затем, поскольку по дизайну приложения, мы можем иметь только одно предупреждение и одно оповещение, мы ищем, присутствует ли уже ранее созданное оповещение и если оно присутствует, удаляем его.
Ниже, для примера приведён пример для Alarm:
if (ScheduledActionService.Find(MY_ALARM) != null)
ScheduledActionService.Remove(MY_ALARM);
Дальше, в обоих функциях создаётся однократное оповещение, которое закончится через 5 минут, после указанного времени.
При этом, для типа Reminder мы задаём заголовок и URI перехода, при нажатии на область уведомления.
Reminder myReminder = new Reminder(MY_REMINDER);
myReminder.Title = NotificationTitle.Text;
myReminder.Content = NotificationText.Text;
myReminder.RecurrenceType = RecurrenceInterval.None;
myReminder.BeginTime = beginTime;
myReminder.ExpirationTime = beginTime.AddMinutes(5);
myReminder.NavigationUri = new Uri("/NotificationList.xaml",
UriKind.RelativeOrAbsolute);
ScheduledActionService.Add(myReminder);
Теперь осталось добавить в XAML код ссылку на обработчик события Click:
<Button Content="установить" Name="SetNotification" FontSize="22.667"
Width="450" Click="SetNotification_Click" />
И добавить в код простой обработчик:
private void SetNotification_Click(object sender, RoutedEventArgs e)
{
if ((bool)AlarmType.IsChecked)
CreateAlarm();
if ((bool)ReminderType.IsChecked)
CreateReminder();
}
Соберите приложение, запустите его (F5) и проверьте, как оно работает.