Основы разработки приложений беспроводных устройств

Лабораторный практикум 4

Показывать лекцию целиком

Лабораторная работа №16. Фоновая служба

Задание

Создать приложение Windows Phone 7, запускающее фоновую службу, которая при активации меняет тайлы приложения.

Освоение

  • фоновые службы
  • тайлы (изображения, отображающиеся на главной странице)
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application. Разметка главной страницы будет состоять из 2 кнопок при нажатии на которые мы будем запускать и останавливать фоновую службу:

    <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <StackPanel>
                    <TextBlock Text="Служба для периодической смены тайлов приложения." 
                    FontSize="26" Height="460" TextWrapping="Wrap" />
                    <Button Name="btnSvcStart" Content="Запустить службу" 
                    Click="btnSvcStart_Click" />
                    <Button Name="btnSvcStop" Content="Остановить службу" 
                    Click="btnSvcStop_Click" />
                </StackPanel>
            </Grid>
    

    Добавим в решение (solution) новый проект Silverlight for Windows Phone – Windows Phone Scheduled Task Agent.

    В наш основной проект добавим ссылку на проект службы: Add Reference… – Projects - <имя проекта службы>. Также добавим несколько изображений размера 173x173 (для тайлов). Назовем их, например, "Tile01.png", "Tile02.png", …, "Tile05.png". Установим для данных изображений свойство "Build Action" в "Content".

    Примечание: тайлы – это изображения, отображающиеся на главной странице Windows Phone 7. Они могут иметь пояснительные надписи и обратную сторону – другое изображение, которое будет периодически появляться. Для того чтобы добавить тайл приложения на главную страницу, в списке приложений нажмите на ваше приложение и удерживайте. В появившемся контекстном меню выберете "pin to start" Рис. 5.1 :

    (рис 5.1) Отображение тайла приложения на главной странице

    В проекте службы в методе OnInvoke() будем задавать логику работы службы – смену изображения для тайла приложения. Для определения текущего номера будем пользоваться изолированным хранилищем (либо можно определять тайл случайным образом).

    protected override void OnInvoke(ScheduledTask task)
            {
                //TODO: Add code to perform your task in background
    
                int nTileNumber = 0;
    
                if (IsIsolatedStorageExist())
                {
                    string strTileNum = LoadFromIsolatedStorage();
                    nTileNumber = int.Parse(strTileNum);
                }
    
                const int MAX_TILE_NUMBER = 5;
    
                nTileNumber++;
                if (nTileNumber > MAX_TILE_NUMBER) nTileNumber = 1;
                string strTileName = "/Tiles/Tile0" + nTileNumber.ToString() + ".png";
                SetTile(strTileName);
                SaveToIsolatedStorage(nTileNumber.ToString());
    
    #if DEBUG
                ScheduledActionService.LaunchForTest(task.Name, System.TimeSpan.FromSeconds(10));
    #endif
    
                NotifyComplete();
            }
    
            private void SetTile(string strPath)
            {
                ShellTile apptile = ShellTile.ActiveTiles.First();
    
                StandardTileData appTileData = new StandardTileData();
                appTileData.Title = "Служба";
                appTileData.Count = 0;
                appTileData.BackgroundImage = new Uri(strPath, UriKind.RelativeOrAbsolute);
    
                apptile.Update(appTileData);
            }
    

    Для работы данного кода необходимо добавить следующие директивы:

    using System;
    using System.Linq;
    using Microsoft.Phone.Shell;
    

    Конструкция

    #if DEBUG
                ScheduledActionService.LaunchForTest(task.Name, System.TimeSpan.FromSeconds(10));
    #endif
    

    позволяет в отладочном режиме вызывать службу каждые 10 секунд.

    Вернемся к основному проекту. Объявим в классе константу с именем службы:

            private const string AGENT_NAME = "Agent_Wp7IUSLab22";
    

    Для работы со службами добавим директиву:

            using Microsoft.Phone.Scheduler;
    

    При запуске службы сначала будем проверять, существует ли служба с таким именем (если существует – будем удалять), а затем будем запускать ее. При остановке будем удалять ее и очищать изолированное хранилище.

    private void btnSvcStart_Click(object sender, RoutedEventArgs e)
            {
                //ищем службу
                PeriodicTask myPeriodicTask = ScheduledActionService.Find(AGENT_NAME) as PeriodicTask;
    
                //если нашли
                if (myPeriodicTask != null)
                {
                    try
                    {
                        //удаляем
                        ScheduledActionService.Remove(AGENT_NAME);
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Невозможно удалить ранее созданную службу: " + ex.Message);
                    }
                }
    
                //создаем службу
                myPeriodicTask = new PeriodicTask(AGENT_NAME);
                myPeriodicTask.Description = "Служба для периодической смены тайлов приложения.";
    
                try
                {
                    ScheduledActionService.Add(myPeriodicTask);
    
    #if DEBUG
                    ScheduledActionService.LaunchForTest(AGENT_NAME, TimeSpan.FromSeconds(5));
    #endif
    
                    MessageBox.Show("Служба запущена.");
    
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Невозможно создать службу: " + ex.Message);
                }
            }
    
            private void btnSvcStop_Click(object sender, RoutedEventArgs e)
            {
                //ищем службу
                PeriodicTask myPeriodicTask = ScheduledActionService.Find(AGENT_NAME) as PeriodicTask;
    
                //если нашли
                if (myPeriodicTask != null)
                {
                    try
                    {
                        //удаляем
                        ScheduledActionService.Remove(AGENT_NAME);
                        RemoveIsolatedStorage();
    
                        MessageBox.Show("Служба остановлена.");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("Невозможно удалить службу: " + ex.Message);
                    }
                }
            }
    

    Лабораторная работа №17. Фоновая загрузка файлов

    Задание

    Изменить приложение "RSS-новости", добавив поддержку фоновой загрузки RSS-файлов. Добавить для приложения двусторонний тайл.

    Освоение

  • фоновая загрузка файлов
  • тайлы
  • Описание

    Откроем ранее созданный проект "RSS-новости". Добавим два изображения размера 173x173 (для тайлов). Назовем их, например, "RSSred.png" и "RSSblue.png". Установим для данных изображений свойство "Build Action" в "Content".

    Примечание: тайлы – это изображения, отображающиеся на главной странице Windows Phone 7. Они могут иметь пояснительные надписи и обратную сторону – другое изображение, которое будет периодически появляться. Для того чтобы добавить тайл приложения на главную страницу, в списке приложений нажмите на ваше приложение и удерживайте. В появившемся контекстном меню выберете "pin to start" Рис. 5.2 :

    (рис 5.2) Отображение тайла приложения на главной странице

    В код главной страницы добавим функцию установки тайла. Для основной картинки будем задавать RSSred.png, для обратной RSSblue.png.

    private void SetTile()
            {
                ShellTile apptile = ShellTile.ActiveTiles.First();
    
                StandardTileData appTileData = new StandardTileData();
                appTileData.Title = "RSS новости";
                appTileData.Count = 0;
                appTileData.BackgroundImage = new Uri("/RSSred.png", UriKind.RelativeOrAbsolute);
    
                appTileData.BackTitle = "RSS новости";
                appTileData.BackContent = "Обратная сторона";
                appTileData.BackBackgroundImage = new Uri("/RSSblue.png", UriKind.RelativeOrAbsolute);
    
                apptile.Update(appTileData);
            }
    

    В конструктор класса добавим:

    SetTile();
    

    Также в коде должна быть добавлена директива:

    using Microsoft.Phone.Shell;
    

    Теперь добавим запуск запроса на фоновую загрузку RSS-файла. Для этого в конструктор класса добавим проверку, что в изолированном хранилище приложения присутствует специальная папка, в которую можно загружать файлы, используя фоновые сервисы: "/shared/transfers":

    using (IsolatedStorageFile rssStore = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!rssStore.DirectoryExists("/shared/transfers"))
                {
                    rssStore.CreateDirectory("/shared/transfers");
                }
            }
    

    В код добавим директиву:

    using Microsoft.Phone.BackgroundTransfer;
    

    В функции LoadRSS() будем запускать фоновую загрузку нужного файла, а также подписываться на изменение статуса загрузки:

    private void LoadRSS(Uri url)
            {
                BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(url);
    
                transferRequest.Method = "GET";
    
                string strRSSFileName = "";
    
                switch (m_nRssLoadIndex)
                {
                    case 0:
                        strRSSFileName = strIStoragePolit;
                        break;
                    case 1:
                        strRSSFileName = strIStorageEconom;
                        break;
                    case 2:
                        strRSSFileName = strIStorageSport;
                        break;
                    case 3:
                        strRSSFileName = strIStorageMusic;
                        break;
                    case 4:
                        strRSSFileName = strIStorageMsdn;
                        break;
                    default:
                        MessageBox.Show("Ошибка при загрузке новостей.");
                        return;
                }
    
                Uri downloadUri = new Uri("shared/transfers/" + strRSSFileName, UriKind.RelativeOrAbsolute);
                transferRequest.DownloadLocation = downloadUri;
    
                transferRequest.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>
    (transferRequest_TransferStatusChanged);
    
                try
                {
                    BackgroundTransferService.Add(transferRequest);
                }
                catch (Exception ex)
                {
    
                    MessageBox.Show("Невозможно запустить фоновую загрузку:" + ex.Message);
                }
            }
    

    По завершении загрузки будем удалять фоновую загрузку, затем копировать загруженный файл из папки "/shared/transfers/" в корень изолированного хранилища, а затем работать с файлом, как прежде.

    void transferRequest_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
            {
                //если скачивание прошло успешно - копируем файл и обновляем UI
                if (e.Request.TransferStatus == TransferStatus.Completed)
                {
                    try
                    {
                        BackgroundTransferService.Remove(e.Request);
                    }
                    catch (Exception ex)
                    {
    
                        MessageBox.Show("Невозможно удалить завершенную фоновую загрузку:" + ex.Message);
                    }
    
                    using (IsolatedStorageFile rssStore = IsolatedStorageFile.GetUserStoreForApplication())
                    {
                        string strRSSFileName = "";
    
                        switch (m_nRssLoadIndex)
                        {
                            case 0:
                                strRSSFileName = strIStoragePolit;
                                break;
                            case 1:
                                strRSSFileName = strIStorageEconom;
                                break;
                            case 2:
                                strRSSFileName = strIStorageSport;
                                break;
                            case 3:
                                strRSSFileName = strIStorageMusic;
                                break;
                            case 4:
                                strRSSFileName = strIStorageMsdn;
                                break;
                            default:
                                MessageBox.Show("Ошибка при загрузке новостей.");
                                return;
                            //break;
                        }
    
                        if (rssStore.FileExists("/shared/transfers/" + strRSSFileName))
                        {
                            rssStore.CopyFile("/shared/transfers/" + strRSSFileName, strRSSFileName, true);
    
                            string strRSSNews = LoadFromIsolatedStorage(strRSSFileName);
                            ParseAndDislayRSS(strRSSNews, false);
                        }
                    }
    
                }
            }
    

    Теперь всю функциональность, касающуюся WebClient, можно убрать.

    Лабораторная работа №18. Проигрыватель музыки

    Задание

    Создать приложение для Windows Phone 7, проигрывающее музыку в фоне. Предусмотреть возможность перехода к предыдущей/следующей песне и постановки на паузу. Добавить для приложения тайл, который будет меняться при проигрывании песни.

    Освоение

  • фоновое воспроизведение музыки
  • тайлы
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Добавим в него папку Audio, а в нее несколько аудио-файлов, формат которых поддерживает Windows Phone 7. Установим значение свойства "Build Action" в "Content", а "Copy to Output Directory" в "Copy if newer".

    Добавим два изображения размера 173x173 (для тайлов). Назовем их, например, "Tile1.png" и "Tile2.png". Установим для данных изображений свойство "Build Action" в "Content".

    Примечание: тайлы – это изображения, отображающиеся на главной странице Windows Phone 7. Они могут иметь пояснительные надписи и обратную сторону – другое изображение, которое будет периодически появляться. Для того чтобы добавить тайл приложения на главную страницу, в списке приложений нажмите на ваше приложение и удерживайте. В появившемся контекстном меню выберете "pin to start" Рис. 5.3 :

    (рис 5.3) Отображение тайла приложения на главной странице

    В код главной страницы добавим функцию установки тайла. При проигрывании мелодии в параметр IsPlay будем передавать true, в противном случае – false.

    private void SetTile(bool IsPlay = false)
            {
                ShellTile apptile = ShellTile.ActiveTiles.First();
    
                StandardTileData appTileData = new StandardTileData();
                appTileData.Title = "";
                appTileData.Count = 0;
    
                if (IsPlay)
                {
                    appTileData.BackgroundImage = new Uri("/Tile2.png", UriKind.RelativeOrAbsolute);
                }
                else
                {
                    appTileData.BackgroundImage = new Uri("/Tile1.png", UriKind.RelativeOrAbsolute);
                }
    
                apptile.Update(appTileData);
            }
    

    В конструктор класса добавим:

    SetTile();
    

    Также в коде должна быть добавлена директива:

    using Microsoft.Phone.Shell;
    

    Теперь добавим в решение (solution) новый проект Silverlight for Windows Phone – Windows Phone Audio Playback Agent. В наш основной проект добавим ссылку на данный проект: Add Reference… – Projects - <имя проекта аудио-плейера>.

    В файл AudioPlayer.cs добавим директиву:

    using System.Collections.Generic;
    

    Затем в класс добавим две глобальные переменные: номер текущей песни и список песен. В список песен сразу добавим имена файлов наших песен. Также можно указать название, автора и альбом.

    private static int currentTrackNumber = 0;
    
            private static List<AudioTrack>_playList = new List<AudioTrack>
            {
                new AudioTrack(new Uri("Elena Gheorghe - Balkan Girls.mp3", UriKind.Relative), 
                                "Balkan Girls", 
                                "Elena Gheorghe", 
                                "Eurovision 2010", 
                                null),
    
                new AudioTrack(new Uri("Lara Fabian - I Guess I Loved You.mp3", UriKind.Relative), 
                                "I Guess I Loved You", 
                                "Lara Fabian", 
                                "Unknown", 
                                null),
    
                new AudioTrack(new Uri("velvet-prodavec_kukol.mp3", UriKind.Relative), 
                                "Продавец кукол", 
                                "Вельвет", 
                                "Unknown", 
                                null),
    
                //remote URI
                new AudioTrack(new Uri("http://traffic.libsyn.com/wpradio/WPRadio_29.mp3", UriKind.Absolute), 
                                "Episode 29", 
                                "Windows Phone Radio", 
                                "Windows Phone Radio Podcast", 
                                null)
            };
    

    Добавим в класс три метода:

    private void PlayNextTrack(BackgroundAudioPlayer player)
            {
                if (++currentTrackNumber >= _playList.Count)
                {
                    currentTrackNumber = 0;
                }
    
                PlayTrack(player);
            }
    
            private void PlayPreviousTrack(BackgroundAudioPlayer player)
            {
                if (--currentTrackNumber < 0)
                {
                    currentTrackNumber = _playList.Count - 1;
                }
    
                PlayTrack(player);
            }
    
            private void PlayTrack(BackgroundAudioPlayer player)
            {
                // Sets the track to play. When the TrackReady state is received, 
                // playback begins from the OnPlayStateChanged handler.
                player.Track = _playList[currentTrackNumber];
            }
    

    Изменим функции OnPlayStateChanged() и OnUserAction() :

    protected override void OnPlayStateChanged(BackgroundAudioPlayer player, 
    AudioTrack track, PlayState playState)
            {
                switch (playState)
                {
                    case PlayState.TrackReady:
                        // The track to play is set in the PlayTrack method.
                        player.Play();
                        break;
    
                    case PlayState.TrackEnded:
                        PlayNextTrack(player);
                        break;
                }
    
                NotifyComplete();
            }
    
            protected override void OnUserAction(BackgroundAudioPlayer player, 
              AudioTrack track, UserAction action, object param)
            {
                switch (action)
                {
                    case UserAction.Play:
                        if (isPaused)
                            player.Play();
                        else
                            PlayTrack(player);
                        
                        isPaused = false;
                        break;
    
                    case UserAction.Pause:
                        player.Pause();
                        isPaused = true;
                        break;
    
                    case UserAction.SkipPrevious:
                        PlayPreviousTrack(player);
                        isPaused = false;
                        break;
    
                    case UserAction.SkipNext:
                        PlayNextTrack(player);
                        isPaused = false;
                        break;
                }
    
                NotifyComplete();
            }
    

    Теперь откроем файл App.xaml основного проекта.

    Добавим 2 директивы:

    using System.IO.IsolatedStorage;
    using System.Windows.Resources;
    

    Поскольку фоновый аудио-проигрыватель умеет воспроизводить музыку только из изолированного проигрывателя, добавим в класс App функцию, которая будет копировать в проигрыватель песни из ресурсов. Вызов функции добавим в конструктор класса.

            private void CopyToIsolatedStorage()
            {
                using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    string[] files = new string[] { "Elena Gheorghe - Balkan Girls.mp3",
                                                    "Lara Fabian - I Guess I Loved You.mp3",
                                                    "velvet-prodavec_kukol.mp3" };
    
                    foreach (var _fileName in files)
                    {
                        if (!storage.FileExists(_fileName))
                        {
                            string _filePath = "Audio/" + _fileName;
                            StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));
    
                            using (IsolatedStorageFileStream file = storage.CreateFile(_fileName))
                            {
                                int chunkSize = 4096;
                                byte[] bytes = new byte[chunkSize];
                                int byteCount;
    
                                while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)
                                {
                                    file.Write(bytes, 0, byteCount);
                                }
                            }
                        }
                    }
                }
            }
    

    Вернемся к главной странице. В файл разметки добавим несколько текстовых блоков для вывода информации о текущей песне и меню, состоящее из 3 кнопок: назад, воспроизведение/пауза, вперед.

    Теперь перейдем к коду главной страницы. Добавим директиву:

    using Microsoft.Phone.BackgroundAudio;
    

    В конструкторе подпишемся на изменение состояния воспроизведения:

     BackgroundAudioPlayer.Instance.PlayStateChanged += new EventHandler(Instance_PlayStateChanged);
    

    Добавим обработчик события:

            void Instance_PlayStateChanged(object sender, EventArgs e)
            {
                switch (BackgroundAudioPlayer.Instance.PlayerState)
                {
                    case PlayState.Playing:
                        ((ApplicationBarIconButton)ApplicationBar.Buttons[1])
                         .IconUri = new Uri(PATH_TO_PAUSE_IMG, UriKind.Relative);
                        SetTile(true);
                        break;
    
                    case PlayState.Paused:
                    case PlayState.Stopped:
                        ((ApplicationBarIconButton)ApplicationBar.Buttons[1])
                          .IconUri = new Uri(PATH_TO_PLAY_IMG, UriKind.Relative);
                        SetTile(false);
                        break;
                }
    
                if (null != BackgroundAudioPlayer.Instance.Track)
                {
                    txtAuthor.Text = BackgroundAudioPlayer.Instance.Track.Artist;
                    txtAlbum.Text = BackgroundAudioPlayer.Instance.Track.Album;
                    txtDur.Text = String.Format("{0:00}", BackgroundAudioPlayer.Instance.Track.Duration.Minutes) + ":" +
                                    String.Format("{0:00}", BackgroundAudioPlayer.Instance.Track.Duration.Seconds);
    
                    PageTitle.Text = BackgroundAudioPlayer.Instance.Track.Title;
    
                    ...
                }
            }
    

    Обработчики нажатий на кнопки меню:

                  private void Menu1_Click(object sender, EventArgs e)
            {
                BackgroundAudioPlayer.Instance.SkipPrevious();
            }
    
            private void Menu2_Click(object sender, EventArgs e)
            {
                if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
                {
                    BackgroundAudioPlayer.Instance.Pause();
                }
                else
                {
                    BackgroundAudioPlayer.Instance.Play();
    
                }
            }
    
            private void Menu3_Click(object sender, EventArgs e)
            {
                BackgroundAudioPlayer.Instance.SkipNext();
            }
    

    При закрытии приложения музыка будет продолжать воспроизводиться. При повторном открытии приложения будем выдавать пользователю информацию о текущей песне. Для этого переопределим метод OnNavigatedTo() главной страницы:

          protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                //если при хагрузке приложения уже играет музыка
                if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
                {
                    txtAuthor.Text = BackgroundAudioPlayer.Instance.Track.Artist;
                    txtAlbum.Text = BackgroundAudioPlayer.Instance.Track.Album;
                    txtDur.Text = String.Format("{0:00}", BackgroundAudioPlayer.Instance.Track.Duration.Minutes) + ":" +
                                    String.Format("{0:00}", BackgroundAudioPlayer.Instance.Track.Duration.Seconds);
    
                    PageTitle.Text = BackgroundAudioPlayer.Instance.Track.Title;
                    ((ApplicationBarIconButton)ApplicationBar.Buttons[1])
                          .IconUri = new Uri(PATH_TO_PAUSE_IMG, UriKind.Relative);
    
                    ...
                }
                else
                {
                    txtAuthor.Text = "";
                    txtAlbum.Text = "";
                    txtDur.Text = "";
    
                    PageTitle.Text = PAGE_DEFAULT_TITLE_TEXT;
                    ((ApplicationBarIconButton)ApplicationBar.Buttons[1]).IconUri =
                          new Uri(PATH_TO_PLAY_IMG, UriKind.Relative);
    
                    ...
                }
            }
    

    Лабораторная работа №19. Список задач с напоминаниями

    Задание

    Изменить приложение "Список задач", добавив установку напоминаний. Добавить для приложения двусторонний тайл.

    Освоение

  • напоминания
  • тайлы
  • Описание

    Откроем проект "Список задач". Добавим два изображения размера 173x173 (для тайлов). Назовем их, например, "Front.png" и "Background.png". Установим для данных изображений свойство "Build Action" в "Content".

    Примечание: тайлы – это изображения, отображающиеся на главной странице Windows Phone 7. Они могут иметь пояснительные надписи и обратную сторону – другое изображение, которое будет периодически появляться. Для того чтобы добавить тайл приложения на главную страницу, в списке приложений нажмите на ваше приложение и удерживайте. В появившемся контекстном меню выберете "pin to start" Рис. 5.4 :

    (рис 5.4) Отображение тайла приложения на главной странице

    В код главной страницы добавим функцию установки тайла. В качестве основной картинки установим "Front.png", в качестве обратной – "Background.png".

        private void SetTile()
            {
                ShellTile apptile = ShellTile.ActiveTiles.First();
    
                StandardTileData appTileData = new StandardTileData();
                appTileData.Title = "Список задач";
                appTileData.Count = 0;
                appTileData.BackgroundImage = new Uri("/Front.png", UriKind.RelativeOrAbsolute);
    
                appTileData.BackTitle = "Список задач";
                appTileData.BackContent = "Обратная сторона";
                appTileData.BackBackgroundImage = new Uri("/Background.png", UriKind.RelativeOrAbsolute);
    
                apptile.Update(appTileData);
            }
     

    В конструктор класса добавим:

         SetTile();
    

    Также в коде должна быть добавлена директива:

       using Microsoft.Phone.Shell;
    

    В код страницы AddItem.xaml добавим директиву, необходимую для установки напоминаний:

      using Microsoft.Phone.Scheduler;
    

    В класс добавим две константы: базовое имя напоминания (напоминание должно иметь уникальное имя, которое мы будем создавать на основе базового, например, добавлением номера) и максимальное количество.

      private const string REMINDER_BASE_NAME = "reminder";
            private const int MAX_REMINDER_COUNT = 3;
    

    Функцию генерации имени рекомендуется написать самостоятельно.

    Изменим функцию добавления напоминания:

     private void btnSet_Click(object sender, RoutedEventArgs e)
            {
                //генерируем имя напоминания
                string strName = GenerateReminderName();
    
                if (!strName.Equals(""))
                {
                    if (!txtTitle.Text.Trim().Equals("")  !txtText.Text.Trim().Equals(""))
                    {
                        DateTime date = (DateTime)ToDoItemDate.Value;
                        DateTime time = (DateTime)ToDoItemTime.Value;
                        DateTime beginTime = date + time.TimeOfDay;
    
                        if (beginTime > DateTime.Now)
                        {
                            CreateReminder(strName, beginTime);
    
                            NavigationService.GoBack();
                        }
                        else
                        {
                            MessageBox.Show("Невозможно установить задачу на прошлое.");
                        }
                    }
                    else
                    {
                        MessageBox.Show("Не все поля заполнены.");
                    }
                }
                else
                {
                    MessageBox.Show("Нельзя создать больше " + MAX_REMINDER_COUNT + " задач.");
                }
            }
    
            private void CreateReminder(string strName, DateTime beginTime)
            {
                Reminder myReminder = new Reminder(strName);
                myReminder.Title = txtTitle.Text;
                myReminder.Content = txtText.Text;
                
                myReminder.RecurrenceType = RecurrenceInterval.None;
                myReminder.BeginTime = beginTime;
                myReminder.ExpirationTime = beginTime.AddMinutes(5);
                myReminder.NavigationUri = new Uri("/MainPage.xaml", UriKind.Relative);
    
                ScheduledActionService.Add(myReminder);
            }
    

    Свойство NavigationUri задает ссылку на страницу приложения, которая должна быть запущена при нажатии на напоминание.

    Вернемся к коду главной страницы. Добавим функцию инициализации списка. Будем получать коллекцию напоминаний, считать их количество и обновлять тайл (свойству count задавать количество зарегистрированных напоминаний):

     private void InitList()
            {
                listToDo.ItemsSource = ScheduledActionService.GetActions<ScheduledNotification>();
    
                int count = 0;
    
                foreach (Reminder ri in listToDo.ItemsSource)
                {
    
                    count++;
                }
    
                //update tile
                ShellTile apptile = ShellTile.ActiveTiles.First();
                StandardTileData appTileData = new StandardTileData();
                appTileData.Count = count;
                apptile.Update(appTileData);
            }
    

    Не забудем добавить пространство имен для кода главной страницы Microsoft.Phone.Scheduler.

    В связи с новой функциональностью перепишем метод OnNavigatedTo() и обработчик нажатия на кнопку "Удалить":

             protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                InitList();
            }
    
            private void MenuRemove_Click(object sender, EventArgs e)
            {
                if (-1 != listToDo.SelectedIndex)
                {
                    string strName = ((Reminder)listToDo.SelectedItem).Name;
    
                    if (null != ScheduledActionService.Find(strName))
                    {
                        ScheduledActionService.Remove(strName);
    
                        InitList();
                    }
                }
                else
                {
                    MessageBox.Show("Нет выделенных элементов.");
                }
            }
    

    Также перепишем разметку страницы с использованием шаблонов (источник данных для списка задается в функции InitList()):

         <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <ListBox Name="listToDo">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Title}" FontSize="26" FontWeight="Bold" />
                                <TextBlock Text="{Binding Content}" FontSize="24" TextWrapping="Wrap" />
                                <TextBlock Text="{Binding BeginTime}" FontSize="24" FontStyle="Italic" />
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </Grid>
      

    Лабораторная работа №20. Будильник

    Задание

    Создать приложение для Windows Phone 7, позволяющее устанавливать ежедневные будильники с возможностью выбора мелодии. Приложение должно иметь свой тайл.

    Освоение

  • Бужильники
  • тайлы
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Добавим изображение размера 173x173 (для тайла). Назовем его, например, "Front.png". Установим для данных изображений свойство "Build Action" в "Content".

    Примечание: тайлы – это изображения, отображающиеся на главной странице Windows Phone 7. Они могут иметь пояснительные надписи и обратную сторону – другое изображение, которое будет периодически появляться. Для того чтобы добавить тайл приложения на главную страницу, в списке приложений нажмите на ваше приложение и удерживайте. В появившемся контекстном меню выберете "pin to start" Рис. 5.5:

    (рис 5.5) Отображение тайла приложения на главной странице

    В код главной страницы добавим функцию установки тайла:

         private void SetTile()
            {
                ShellTile apptile = ShellTile.ActiveTiles.First();
    
                StandardTileData appTileData = new StandardTileData();
                appTileData.Title = "Будильник";
                appTileData.Count = 0;
                appTileData.BackgroundImage = new Uri("/Front.png", UriKind.RelativeOrAbsolute);
    
                apptile.Update(appTileData);
            }
    

    В конструктор класса добавим:

            SetTile();    
    

    Также в коде должна быть добавлена директива:

            using Microsoft.Phone.Shell;
    

    Создадим в проекте папку Audio. Добавим в нее несколько музыкальных файлов формата, который поддерживается Windows Phone 7. Свойство "Build Action" для этих файлов установим в "Content".

    Добавим в проект страницу AddAlarm.xaml. В References добавим пространство имен Microsoft.Phone.Controls.Toolkit. Основное содержимое разметки будет выглядеть следующим образом:

           <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <StackPanel Margin="15,15,0,0">
                    <TextBlock Text="Текст:"  FontSize="26" />
                    <TextBox Name="txtText" FontSize="26" />
    
                    <TextBlock Text="Мелодия:" FontSize="26" VerticalAlignment="Center" />
                    <toolkit:ListPicker Name="lpSound">
                        <toolkit:ListPickerItem Content="After Forever - Living Shields.mp3" />
                        <toolkit:ListPickerItem Content="Ancient Bards - The Birth Of Evil.mp3" />
                    </toolkit:ListPicker>
    
                    <TextBlock Text="Время:" FontSize="26" VerticalAlignment="Center" />
                    <toolkit:TimePicker Name="ToDoItemTime"/>
    
                    <StackPanel Orientation="Horizontal" Margin="0,20,0,0">
                        <Button Name="btnBack" Content="<-" Width="100" Click="btnBack_Click" />
                        <Button Name="btnSet" Content="Установить" Width="340" Click="btnSet_Click" />
                    </StackPanel>
                </StackPanel>
            </Grid>
    

    Элемент управления ListPicker будет содержать названия файлов с мелодиями.

    В коде страницы добавим директиву, необходимую для установки напоминаний:

            using Microsoft.Phone.Scheduler;
    

    В класс добавим две константы: базовое имя будильника (будильник должен иметь уникальное имя, которое мы будем создавать на основе базового, например, добавлением номера) и максимальное количество будильников.

            private const string ALARM_BASE_NAME = "alarm";
            private const int MAX_ALARM_COUNT = 3;
    

    Функцию генерации имени рекомендуется написать самостоятельно.

    Добавим функции создания будильников:

            private void btnSet_Click(object sender, RoutedEventArgs e)
            {
                //генерируем имя напоминания
                string strName = GenerateAlarmName();
    
                if (!strName.Equals(""))
                {
                    if (!txtText.Text.Trim().Equals(""))
                    {
                        DateTime beginTime = (DateTime)ToDoItemTime.Value;
    
                        CreateAlarm(strName, beginTime);
                    }
                    else
                    {
                        MessageBox.Show("Не все поля заполнены.");
                    }
                }
                else
                {
                    MessageBox.Show("Нельзя создать больше " + MAX_ALARM_COUNT + " будильников.");
                }
            }
    
            private void CreateAlarm(string strName, DateTime beginTime)
            {
                Alarm myAlarm = new Alarm(strName);
                myAlarm.Content = txtText.Text;
    
                string strAudio = "/Audio/" + ((ListPickerItem)lpSound.SelectedItem).Content;
                myAlarm.Sound = new Uri(strAudio, UriKind.Relative);
    
                myAlarm.RecurrenceType = RecurrenceInterval.Daily;
                myAlarm.BeginTime = beginTime;
    
                ScheduledActionService.Add(myAlarm);
            }
    

    Перейдем к коду главной страницы. Добавим функцию инициализации списка. Будем получать коллекцию будильников, считать их количество и обновлять тайл (свойству count задавать количество зарегистрированных будильников):

          private void InitList()
            {
                listAlarms.ItemsSource = ScheduledActionService.GetActions<ScheduledNotification>();
    
                int count = 0;
    
                foreach (Alarm ri in listAlarms.ItemsSource)
                {
                    count++;
                }
    
                //update tile
                ShellTile apptile = ShellTile.ActiveTiles.First();
                StandardTileData appTileData = new StandardTileData();
                appTileData.Count = count;
                apptile.Update(appTileData);
            }
    

    Не забудем добавить пространство имен для кода главной страницы Microsoft.Phone.Scheduler.

    Вызывать функцию инициализации будем в методе OnNavigatedTo():

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                InitList();
            }
    

    Напишем разметку страницы с использованием шаблонов (источник данных для списка задается в функции InitList()):

        <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <ListBox Name="listAlarms">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Title}" FontSize="26" 
                                TextWrapping="NoWrap" FontWeight="Bold" />
                                <TextBlock Text="{Binding Content}" FontSize="24" 
                                TextWrapping="Wrap" />
                                <TextBlock Text="{Binding BeginTime}" FontSize="24" 
                                FontStyle="Italic" />
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </Grid>
    

    Добавим две кнопки в меню: добавление нового будильника и удаление.

       <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar.add.rest.png" 
                Text="добавить" Click="MenuAdd_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar.delete.rest.png" 
                Text="удалить" Click="MenuRemove_Click" />
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    Напишем обработчик нажатия на кнопку удаления:

      private void MenuRemove_Click(object sender, EventArgs e)
            {
                if (-1 != listAlarms.SelectedIndex)
                {
                    string strName = ((Alarm)listAlarms.SelectedItem).Name;
    
                    if (null != ScheduledActionService.Find(strName))
                    {
                        ScheduledActionService.Remove(strName);
    
                        InitList();
                    }
                }
                else
                {
                    MessageBox.Show("Нет выделенных элементов.");
                }
            }
    
    Вернуться к учебному плану