Архив

Публикации с меткой ‘Silverlight’

45 дней с Windows Phone 7. День #16. Элемент управления Panorama.

<< День #15. Изолированное хранилище.День #17. Элемент управления Pivot >>

Это шестнадцатая статья серии «45 дней с Windows Phone 7».

Вчера мы говорили про изолированное хранилище, и то, как приложения могут сохранять данные на телефоне c Windows Phone 7. Сегодня мы рассмотрим намного менее системную тему, а именно работу с элементом управления «Panorama» (Панорама :) ).

Элемент управления Panorama.

Если Вы смотрели презентации, посвящённые Windows Phone 7, Вы точно видели, как работает элемент управления Panorama. Он применяется очень часто, взять хотя бы те же хабы.

Если вкратце, данный элемент управления представляет собой прокручиваемую область над содержимым, которое является группой секций, выстроенных как бы в ленту. Вот несколько примеров, чтобы было более понятно:

Другой пример, но без наведённого телефона:

Отлично, теперь мы знаем, что Panorama является крутым элементом управления. А значит, теперь поговорим, как использовать его в своих приложениях.

Проект приложения «Panorama Application».

В предыдущих 15 статьях серии каждый проект начинался с самого простого шаблона «Windows Phone Application». Для приложений, использующих панораму, Вы можете применить шаблон проекта «Windows Phone Panorama Application». Конечно, если Вам этого хочется. Панорама представляет собой просто элемент управления, поэтому её можно использовать в любом проекте Windows Phone 7 приложения, и не важно, какой шаблон использовался.

Если Вы забыли, какие проекты доступны, вот их список:

Важно отметить, что шаблон «Windows Phone Panorama Application» использует для построения интерфейса паттерн проектирования MVVM (Model-View-ViewModel) , что даёт нам хороший пример при разработке приложений.

Но для лучшего понимания работы с элементом управления, давайте теперь посмотрим, как с нуля добавить панораму на страницу (шаблон «Windows Phone Panorama Application» мы использовать НЕ будем).

Добавляем Panorama на Toolbox

Панорама не отображается в списке стандартных элементов управления в Toolbox. Поэтому, для добавления панорамы можно выполнить ряд действий руками (например, определить XML пространство имён в XAML коде), а можно один раз добавить панораму на Toolbox, чтобы потом её достаточно было просто перетащить нужную страницу.

Для этого в контекстном меню вкладки «Windows Phone controls» на Toolbox выберите пункт «Choose Items…»

В открывшимся диалоге на вкладке «Windows Phone Components» отметьте элемент управления Panorama (завтра мы будем говорить про элемент управления Pivot, так что сейчас можете добавить и его).

После нажатия кнопки «OK» нужные нам элементы управления появятся на Toolbox.

Добавляем элемент управления Panorama на страницу.

После того, как мы добавили панораму на Tooolbox, сделав, тем самым, себе жизнь легче, пришло время использовать данный элемент управления. Удалите всё содержимое страницы, на которую будет добавляться панорама (внутри тега «Grid» с именем «LayoutRoot»).

Перетащите панораму на страницу. После этого Вы увидите в XAML коде нечто похожее:

<controls:Panorama />

Не густо. Также можно заметить, что на странице добавлено XML пространство имён:

xmlns:controls=
"clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"

Теперь у нас есть абсолютный минимум кода и никакого пользовательского интерфейса. Давайте добавим этот самый пользовательский интерфейс. Далее приведена иллюстрация того, как выглядят разные части элемента управления Panorama.

Установка фона и заголовка.

Одной из классных «фич» панорамы является возможность иметь одно большое изображение в фоне, которое прокручивается медленнее, чем остальной контент. Для реальных приложений найдите классное изображение, которое отражает суть Вашего приложения. Далее я подобрал фоновое изображение для приложения, которое будет использоваться, чтобы скоротать время во время ожидания еды в ресторане (данное здание, это Corner Grill в Bowling Green).

Для установки данного изображения как фона панорамы, я вначале добавил изображение в проект, а потом для свойства «Background» панорамы задал кисть «ImageBrush», которая использует наше изображение. Кроме того я задал прозрачность (Opacity) для кисти равной 0.5. Это сделано для того, чтобы белый текст лучше читался на данном весьма светлом изображении.

<controls:Panorama Title="waiter">
    <controls:Panorama.Background>
        <ImageBrush ImageSource="PanoramaBackground.jpg" Opacity=".5" />
    </controls:Panorama.Background>
</controls:Panorama>

Кроме того я задал заголовок для панорамы – «waiter» (тот, кто ожидает кого-л. или что-л.).
Вот как теперь выглядит приложение:

Замечательно! У нас есть фон. Теперь пора добавить то, ради чего приложение, собственно, и создаётся – контент.

Создаём PanoramaItem (секцию панорамы).

Сейчас наше приложение работает не очень хорошо. Оно не прокручивается и не показывает ничего кроме фона и заголовка. Добавляя PanoramaItem мы создаём индивидуальные секции панорамы, а уже в PanoramaItem можно добавить XAML разметку, представляющую конкретную секцию.

Каждая секция полностью независима от остальных, поэтому теоретически можно сделать секции выглядящие абсолютно по-разному. Но не стоит перебарщивать.

Далее я добавлю три секции и задам заголовок для каждой из них. Скриншоты каждой секции представлены ниже после кода.

<controls:Panorama Title="waiter">
    <controls:Panorama.Background>
        <ImageBrush ImageSource="PanoramaBackground.jpg" Opacity=".5" />
    </controls:Panorama.Background>
    <controls:PanoramaItem Header="learn">

    </controls:PanoramaItem>
    <controls:PanoramaItem Header="play">

    </controls:PanoramaItem>
    <controls:PanoramaItem Header="all">

    </controls:PanoramaItem>
</controls:Panorama>

Надо отметить, что заголовок панорамы также прокручивается. Но часто не с такой же скоростью, как фон.

Ну что же, теперь приложение выглядит лучше, однако оно до сих пор слишком пустое. Давайте добавим кое-что, чтобы приложение выглядело примерно следующим образом:

Добавляем контент в PanoramaItem.

Конечно, не обязательно, но я бы рекомендовал начать создание секции с добавления ListBox`а. Это даст Вам возможность прокручивать элементы по вертикали. Есть много способов размещать элементы в секции, но ListBox часто оказывается наиболее удобным (кроме того использовать связывание данных в случае ListBox`а очень просто. Прочитайте, что об этом пишет Scott Guthrie).

В моём примере будут элементы, описывающие пять игр, которые, пользователь может запустить, чтобы скоротать время (естественно сейчас самих игр нет, но Вы можете их написать, чтобы потом продавать получившееся приложение в Marketplace). Я создал некоторый XAML код для описания каждой игры и поместил его в ListBox. Далее приведен код получившейся секции «play» и скриншот того, как данная секция выглядит в эмуляторе.

<controls:PanoramaItem Header="play">
    <ListBox Margin="0,0,-12,0">
        <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <Image Height="100" Width="100" Source="icons/tictactoe.png" Margin="12,0,9,0"/>
            <StackPanel Width="311">
                <TextBlock Text="tic tac toe"  TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="the classic two player game" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <Image Height="100" Width="100" Source="icons/numbers.png" Margin="12,0,9,0"/>
            <StackPanel Width="311">
                <TextBlock Text="numbers"  TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="learn your digits from 1 - 20" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <Image Height="100" Width="100" Source="icons/wordsearch.png" Margin="12,0,9,0"/>
            <StackPanel Width="311">
                <TextBlock Text="word search"  TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="find as many words as you can" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <Image Height="100" Width="100" Source="icons/animals.png" Margin="12,0,9,0"/>
            <StackPanel Width="311">
                <TextBlock Text="animals"  TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="hear and learn your favorites" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
            <Image Height="100" Width="100" Source="icons/alphabet.png" Margin="12,0,9,0"/>
            <StackPanel Width="311">
                <TextBlock Text="alphabet"  TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                <TextBlock Text="learn your letters" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
            </StackPanel>
        </StackPanel>
    </ListBox>
</controls:PanoramaItem>

Пример кода.

Пример кода показывает в работе всё, о чём мы говорили в данной статье. Скачайте его и попробуйте панораму в действии!

45 дней с Windows Phone 7. День #15. Изолированное хранилище.

<< День #14. Захоранивание.День #16. Элемент управления Panorama >>

Это пятнадцатая статья серии «45 дней с Windows Phone 7».

Вчера мы говорили о многозадачности в Windows Phone 7, и о том, как сохранять данные приложения при его деактивации. Сегодня мы поговорим про сохранение данных на телефоне, подходящее для любых ситаций. Для этого мы будем использовать механизм изолированного хранилища (Isolated Storage).

Что такое изолированное хранилище?

Изолированное хранилище не новая концепция для .NET вообще и Silverlight в частности. В Silverlight оно поддерживается, начиная со второй версии. Это основной способ для Silverlight приложений сохранить данные на компьютере, а теперь и на телефоне пользователя. Хранилище называется изолированным, так как каждое приложение имеет доступ к своему собственному хранилищу, изолированному от хранилищ других приложений. Здесь и далее речь идёт об изолированном хранилище применительно к телефону. В .NET и Silverlight политики доступа к изолированному хранилищу более разнообразны. Кроме того, важным отличием от Silverlight на компьютере, является то, что в случае телефона у нас нет квоты на размер данных, записываемых в изолированное хранилище. Всё ограничивается только памятью телефона.

Если у Вас есть два приложения, и Вы хотите иметь в них общие данные, лучше воспользуйтесь для этого интернет сервисами. У приложений в Windows Phone 7 нет возможности разделять данные с другими приложениями (в то же время многие данные пользователя, например, фотографии, может получить любое приложение с разрешения самого пользователя) или напрямую взаимодействовать с другими приложениями на устройстве иным образом.

Настройки или файлы.

Есть два способа хранить данные на телефоне. Первый способ – словарь ключ-значение. Данный способ использует класс «IsolatedStorageSettings». Второй способ – создание файлов и папок. При этом используется класс «IsolatedStorageFile». Иллюстрация ниже вкратце показывает оба этих способа.

Далее мы рассмотрим каждый из них подробнее.

IsolatedStorageSettings

Иногда это единственное хранилище, которое Вам требуется. Без какой либо предварительной настройки предоставляется возможность сохранять пары ключ-значение в словаре. Данные сохраняются в памяти телефона и их можно получить после завершения и повторного запуска приложения или даже после выключения-включения телефона. Однако данные, сохранённые в изолированном хранилище приложения, удаляются при деинсталляции самого приложения.

Перед получением конкретного значения надо проверить, присутствует ли ключ в изолированном хранилище. В примере кода ниже сохраняется выбор пользователя (допустим, мы спрашиваем его про то, хочет ли он получать какие-либо обновления по электронной почте). На странице есть CheckBox. То, отмечен ли данный CheckBox сохраняется в изолированном хранилище, а после следующего запуска приложения значение восстанавливается.

Реальные изменения не записываются во flash память телефона, пока мы не вызовем метод «Save()» объекта класса «IsolatedStorageSettings». До этого все изменения происходят только в оперативной памяти. Рекомендуется не вызывать метод «Save()» слишком часто, так как это может негативно сказаться на производительности.

using System.IO.IsolatedStorage;
using System.Windows;
using Microsoft.Phone.Controls;

namespace WindowsPhoneApplication3
{
    public partial class MainPage : PhoneApplicationPage
    {
        readonly IsolatedStorageSettings _settings = 
        IsolatedStorageSettings.ApplicationSettings;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            InitializeSettings();
        }

        private void InitializeSettings()
        {
            if (_settings.Contains("emailFlag"))
            {
                EmailFlag.IsChecked = (bool)_settings["emailFlag"];
            }
            else
            {
                _settings.Add("emailFlag", false);
                _settings.Save();
            }
        }

        private void EmailFlag_Unchecked(object sender, RoutedEventArgs e)
        {
            _settings["emailFlag"] = false;
            _settings.Save();
        }

        private void EmailFlag_Checked(object sender, RoutedEventArgs e)
        {
            _settings["emailFlag"] = true;
            _settings.Save();
        }
    }
}

Как можно видеть всё достаточно просто, но есть несколько вещей, которые следует запомнить.

  • Попытка получения значения по несуществующему ключу всегда будет вызывать «KeyNotFoundException». Перед получением значения, проверьте существование ключа.
  • В данном примере я сохранял булевское значение, но Вы можете сохранять объект любого серилизуемого типа.
  • Помните, что при получении объекта выполняется явное приведение типов. Это прекрасное место для возникновения ошибок.
  • Присвоение значения при отсутствии такового является эквивалентом вызова метода «settings.Add()». В предыдущем примере вызов «settings.Add()» не является обязательным, а используется только для задания значения по умолчанию.

Теперь давайте рассмотрим более сложный сценарий, а именно сохранение файлов в изолированном хранилище.

IsolatedStorageFile

IsolatedStorageFile – это механизм, позволяющий сохранять файлы на телефоне. В примере ниже я сохраняю текстовый файл в подпапке (которую тут же создаю), а потом читаю его содержимое. У нас есть возможность создавать и удалять файлы и папки.

Да, кода больше, чем в примере с IsolatedStorageSettings, но в данном случае он также достаточно прост. Код включает комментарии, так что Вы можете более детально понять что происходит.

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
	//Obtain a virtual store for application
	IsolatedStorageFile fileStorage = 
           IsolatedStorageFile.GetUserStoreForApplication();

	//Create new subdirectory
	fileStorage.CreateDirectory("textFiles");

	//Create a new StreamWriter, 
           //to write the file to the specified location.
	StreamWriter fileWriter = 
           new StreamWriter(new IsolatedStorageFileStream(
           "textFiles\\newText.txt", FileMode.OpenOrCreate, fileStorage));
	//Write the contents of our TextBox to the file.
	fileWriter.WriteLine(writeText.Text);
	//Close the StreamWriter.
	fileWriter.Close();
}

private void GetButton_Click(object sender, RoutedEventArgs e)
{
	//Obtain a virtual store for application
	IsolatedStorageFile fileStorage = 
           IsolatedStorageFile.GetUserStoreForApplication();
	//Create a new StreamReader
	StreamReader fileReader = null;

	try
	{
		//Read the file from the specified location.
		fileReader = new StreamReader(
                      new IsolatedStorageFileStream(
                      "textFiles\\newText.txt", FileMode.Open, fileStorage));
		//Read the contents of the file (the only line we created).
		string textFile = fileReader.ReadLine();

		//Write the contents of the file to the TextBlock on the page.
		viewText.Text = textFile;
		fileReader.Close();
	}
	catch
	{
		//If they click the view button first, 
                    //we need to handle the fact that 
                    //the file hasn't been created yet.
		viewText.Text = "Need to create directory and the file first.";
	}
}

Ну что же, у нас есть два простых механизма сохранения данных: IsolatedStorageSettings и IsolatedStorageFile. Выбирайте то, что больше подходит Вам для каждой конкретной ситуации.

Пример кода.

Код включает пример работы с обоими механизмами сохранения данных.

45 дней с Windows Phone 7. День #14. Захоранивание.

<< День #13. Определение местоположения.День #15. Изолированное хранилище >>

Это четырнадцатая статья серии «45 дней с Windows Phone 7».

В прошлой статье мы говорили о сервисах определения местоположения, что позволяет нашим приложениям лучше подстраиваться под пользователя. Сегодня мы поговорим о, пожалуй, наиболее дискуссионной теме, связанной с Windows Phone 7, а именно о многозадачности.

О Windows Phone 7 написано множество статей, и очень часто недостатком #1 данной операционной системы называют отсутствие многозадачности. Но это не совсем так.

В Windows Phone 7 многозадачность есть.

Да, она есть. Windows Phone 7 представляет собой операционную систему с поддержкой многозадачности. Можно получать e-mail’ы, играя в игры. Или слушать музыку, сидя в интернете. Но для нас, как для разработчиков важно, можем ли мы писать приложения, работающие в фоне. И вообще говоря, ответ нет.

За многие месяцы изучения Windows Phone 7, я вижу только два наиболее важных сценария, для которых может потребоваться работа приложения в фоне, и которые обычные разработчики не могут реализовать на Windows Phone 7.

  1. Приложение играет музыку, как, например Pandora. Слушая on-line радио, пользователь очень расстроится, если оно перестанет играть, как только он перейдёт в другое приложение.
  2. Приложение получает данные от сенсоров. Например, получая данные от сервисов определения местоположения, мы хотим сказать пользователю, когда он будет приближаться к нашему магазину. Но, если пользователь перейдёт в другое приложение, наше приложение перестанет работать, и сообщить мы ничего никому не сможем.

Кроме этих двух сценариев трудно представить ситуацию, когда нам реально нужно работать в фоне. Если Ваше приложение попадает в одну из категорий выше, и Вы являетесь известной и крупной компанией, Вы можете обратиться к Microsoft с просьбой дать доступ к «супер API», чтобы Ваше приложение могло работать в фоне. Но это не для простых смертных.

Перед тем, как Вы скажете: «Но как насчёт получения обновлений от сервера? Разве для этого не нужно работать в фоне???». Мой ответ нет, не нужно. Есть прекрасный механизм оповещений (Push Notifications), который будет рассмотрен в 19 дне и который хорошо решает данную проблему.

Microsoft не разрешает приложениям в Windows Phone 7 работать в фоне по двум причинам:

  1. Большинство пользователей не осознаёт, что когда приложения работают в фоне, они продолжают потреблять системные ресурсы и батарея телефона садится быстрее. (Вы, конечно, к большинству пользователей не относитесь. И на мой взгляд, для гиков нужна отдельная версия операционной системы).
  2. Большинству приложений не требуется работать в фоне.

Ладно, мы не можем работать в фоне, но мы можем притвориться, что наше приложение не закрывалось, чтобы пользователь мог перейти от него к чему-то ещё, а потом вернуться в то же самое место нашего приложения, хотя приложение было закрыто и запущено заново. Данный механизм называется «Захоранивание» («Tombstoning»).

Например, мы пишем приложение-калькулятор. Пользователь считает свои расходы на данном калькуляторе и получает результат. Потом он вспоминает, что забыл прибавить расходы за какую-то покупку, сделанную в интернет магазине. Пользователь открывает браузер, чтобы перейти на сайт интернет магазина и посмотреть цену. В этот момент наш калькулятор деактивируется (закрывается). Но мы сохраняем его состояние. После того, как пользователь узнал цену товара, он снова открывает калькулятор, мы загружаем состояние, и пользователь видит на экране ранее подсчитанную сумму. Всё происходит так, как будто калькулятор работал в фоне. Ниже представлена диаграмма данного процесса:

Если на первом экране приложения пользователь нажмёт кнопку «назад», то приложение не будет деактивировано, а будет закрыто. Так как система по логике должна вернуться в состояние перед запуском приложения. Захоранивание тут не применяется (если нам нужно сохранить при этом какие-то данные, мы естественно можем это сделать).

На диаграмме можно увидеть, что существуют события активации и деактивации, которые мы можем использовать в наших приложениях. Применяя данные события совместно с механизмами изолированного хранилища (Isolated Storage, день #15) и оповещений (день #19), мы можем создавать действительно мощные приложения.

Притворяемся, что приложение работает в фоне.

Если Вы откроете файл «App.xaml.cs» (структура проекта подробно описана в дне #1), Вы можете увидеть несколько обработчиков событий. Далее представлен их код с оставленными комментариями по умолчанию.

// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
}

// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}

// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
}

// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
}

События «Launching» и «Closing» – это традиционные события запуска и заверения приложения (например, соответственно при запуске приложения из списка доступных и нажатии кнопки назад на первом экране приложения). Они не вызываются при деактивации и последующей активации в случае захоранивания. События «Activated» и «Deactivated» вызываются в менее традиционных случаях. Например, когда пользователь жмёт кнопку «Назад» (или телефон разблокируется, а ваше приложение работало до блокировки) чтобы вернуться в Ваше приложение или покидает его, нажав кнопку «Пуск» соответственно (или телефон просто блокируется). Эти события можно использовать для сохранения состояния приложения перед деактивацией и его восстановления после активации.

Сохранение состояния при деактивации.

Если пользователь покидает приложение, нужно сохранить данные. В примере приложения я создаю таймер, который кажется пользователю запущенным, даже при выходе из приложения. Если Вы хотите посмотреть полный код примера, скачайте его в секции «Пример кода». Здесь я покажу только куски кода, относящиеся к захораниванию.

Для сохранения данных я воспользуюсь классом «PhoneApplicationService». Если данных много, лучше воспользоваться изолированным хранилищем, которое будет рассмотрено завтра. В данном примере я сохраняю время, когда пользователь покинул приложение, чтобы подсчитать разницу между тем, когда он приложение покинул и когда вернулся. В реальных приложениях это, разумеется, не лучший подход к построению таймеров.

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
     PhoneApplicationService.Current.State["LeftTime"] = DateTime.Now;
}

Восстановление состояния.

Далее в событии навигации на страницу таймера, я проверяю, содержит ли текущий объект состояния ключ «LeftTime». Если ключ есть, то сохранённое значение используется, если нет, то предполагается, что приложение запущено с нуля. Если спросить пользователя, завершалось ли приложение, он, скорее всего (если не является разработчиком Windows Phone 7 приложений), ответит: нет.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
	base.OnNavigatedTo(e);
	if (PhoneApplicationService.Current.State.ContainsKey("LeftTime"))
	{
	DateTime deactivated = 
           (DateTime)PhoneApplicationService.Current.State["LeftTime"];
	secondsSinceStart = (int)(DateTime.Now - deactivated).TotalSeconds 
            + (int)PhoneApplicationService.Current.State["ElapsedTime"];
	writeTime();
	writeDate();
	timer.Start();
	}
	else secondsSinceStart = 0;
}

Если приложение восстанавливается медленно, на некоторое время на экране телефона может появиться надпись «Resuming». Чтобы снять следующий скриншот я специально замедлил восстановление приложения.

Пример кода.

Ниже приведён более сложный пример таймера, чем показан в данной статье. Запустите приложение и нажмите на эмуляторе кнопку «Пуск» для выходы из приложения, а затем кнопку «Назад» для возвращения в него.

Кроме сохранения значения таймера, в приложении есть текстовое поле, текст в котором тоже сохраняется при захоранивании.

45 дней с Windows Phone 7. День #13. Определение местоположения.

<< День #12. Вибрация.День #14. Захоранивание >>

Это тринадцатая статья серии «45 дней с Windows Phone 7».

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

Почему местоположение так важно?

Знание местоположение телефона позволяет приложению подстраиваться под то, где пользователь находится в данный момент. Например, можно сообщить пользователю, что недалеко от него есть Ваш магазин/кафе/автосервис и.т.д. Клиент социальной сети может сохранять местоположение, чтобы пользователи видели, кто из их друзей находится рядом или кто из друзей уже посещал данное место, а может быть и оставил отзыв.

Сервисы определения местоположения

Есть много путей получения информации о местоположении телефона – это GPS, триангуляция по вышкам сотовой сети, Wi-Fi точки доступа. Далее на картинке представлены сильные и слабые стороны каждого способа.

Наиболее точным способом определения местоположения является GPS (Global Positioning System). При этом используются спутники, поэтому это самый медленный способ. Кроме того, GPS может плохо работать в городах, где много высоких зданий и внутри помещений. Кроме всего прочего GPS потребляет больше всего энергии. Для более быстрого и менее энергозатратного (но и менее точного) получения местоположения может использоваться триангуляция по вышкам сотовой сети.

Перед тем как задумываться о сравнении данных от разных источников и использовании различных способов определения положения, посмотрите на зелёное облако на картинке выше. Microsoft уже обо всём позаботилась. Нам предоставляются сервисы определения местоположения, которые позволяют не задумываться об аппаратных аспектах работы телефона. Мы просто можем сказать, нужна ли нам всегда высокая точность или нет.

Использование сервисов определения местоположения

Получить данные о местоположении достаточно просто. Но перед тем как это сделать, убедитесь, что Ваше приложение декларирует в файле «WMAppManifest.xml» возможность использования сервисов определения местоположения (включено по умолчанию):

<Capability Name="ID_CAP_LOCATION"/>

После этого надо выполнить несколько шагов:

  1. Подключите сборку «System.Device.dll» и пространство имён «System.Device.Location».
  2. Создайте объект класса «GeoCoordinateWatcher».
  3. Подпишитесь на событие изменения местоположения.
  4. Запустите отслеживание местоположения.
  5. Получайте данные.

Далее представлен пример кода, который отображает в текстовых полях «Latitude» и «Longitude» широту и долготу соответственно.

public partial class MainPage : PhoneApplicationPage
{
    private GeoCoordinateWatcher _gcw = new GeoCoordinateWatcher();

    public MainPage()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        _gcw.PositionChanged += _gcw_PositionChanged;
        _gcw.Start();
    }

    void _gcw_PositionChanged(object sender, 
    GeoPositionChangedEventArgs<GeoCoordinate> e)
    {
        Latitude.Text = e.Position.Location.Latitude.ToString();
        Longitude.Text = e.Position.Location.Longitude.ToString();
    }
}

Точность определения местоположения можно задать в конструкторе класса «GeoCoordinateWatcher»:

private GeoCoordinateWatcher _gcw =
new GeoCoordinateWatcher(GeoPositionAccuracy.High);

Точность может принимать значения «Default» и «High».
При изменении местоположения нам передаются следующие данные:

Latitude (Широта) [double] – от -90 до 90 градусов.
Longitude (Долгота) [double] – от -180 до 180 градусов.
Altitude (Высота) [double].
HorizontalAccuracy и VerticalAccuracy [double] – горизонтальная и вертикальная точность соотретственно.
Course (Курс) [double] – от 0 до 360 градусов.
Speed (Скорость) [double].
IsUnknown принимает значение True, когда широта и долгота не являются числами.

Как и в случае с акселерометром эмулятор не предоставляет данные о местоположении. Если Вы запустите код выше на эмуляторе, то не получите никаких данных. Вы можете проверить свойство «Status», объекта класса «GeoCoordinateWatcher», которое в эмуляторе не принимает значений отличных от «NoData». Но, как и данные акселерометра, данные местоположения также можно эмулировать. В этом нам поможет уже знакомый инструмент – Reactive Extensions.

На MSDN представлена статья, описывающая как сделать это: http://msdn.microsoft.com/ru-ru/library/ff637517(VS.92).aspx

Пример кода.

В примере кода я постарался воспользоваться сервисами определения местоположения по максимуму. Пользователь может выбрать точность определения местоположения, запустить и остановить сервисы, а также посмотреть текущее положение на карте. Это значительно более мощный пример, чем представленный выше.

45 дней с Windows Phone 7. День #12. Вибрация.

<< День #11. Работа с акселерометром.День #13. Определение местоположения >>

Это двенадцатая статья серии «45 дней с Windows Phone 7».

В прошлой статье мы говорили о работе с акселерометром на телефонах под управлением Windows Phone 7 и о том, как можно притвориться, что на эмуляторе у нас тоже есть данные акселерометра. Сегодня я расскажу, как заставить телефон вибрировать. Использование вибрации часто требуется для оповещения пользователя о том, что в нашем приложении что-то произошло.

Поскольку, когда говоришь про вибрацию, у людей возникает в голове много различных шуток, можете рассказать их кому-нибудь сейчас, пока я не написал слово «вибрация» ещё раз 15 или 20. Хорошо, я подожду…

Зачем заставлять телефон вибрировать?

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

Обратная связь в играх.

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

Обратная связь для кнопок.

Пользователю будет намного комфортнее, если при нажатии на кнопку, выполняющую критическую важную функцию в приложении, телефон начнёт немного вибрировать. По умолчанию кнопки меняют цвет при нажатии, но пользователь может быть не всегда уверен, действительно ли он данную кнопку нажал. Дайте пользователю обратную связь, говорящую о том, что действие выполнено. Естественно для каждой кнопки такого делать не надо.

Оповещения.

Другим сценарием, когда может быть применена вибрация, являются оповещения. По умолчанию, когда Вы получаете сообщение или e-mail, телефон вибрирует (либо издаёт какой-то звук). Данный подход можно применить и в своих приложениях. Пусть телефон вибрирует, когда пользователю надо что-то сообщить. Например, для приложения, которое постоянно связывается с сервером, потеря соединения с интернетом может быть критичной, сообщите пользователю, если такая ситуация произойдёт.

Как заставить телефон вибрировать?

Заставить телефон вибрировать невероятно просто. Для этого надо написать всего две строчки кода. Но может потребоваться достаточно много времени, чтобы понять, когда и как долго в вашем приложении телефон должен вибрировать, чтобы это было удобно и не раздражало пользователя. Вот пример кода:

VibrateController vc = VibrateController.Default;
vc.Start(TimeSpan.FromMilliseconds(100));

Кроме того, вибрацию можно легко остановить:

Microsoft.Devices.VibrateController.Default.Stop();

Как долго должен вибрировать телефон?

Нет определённых правил, говорящих о том, как долго должен вибрировать телефон. Максимально разрешенное время – пять секунд. Больше нельзя. Если Вы попробуете задать больший интервал, данная попытка породит исключение. Почти всегда, основываясь на здравом смысле, вибрация длится меньшее время. Самое меньшее время, которое телефон может вибрировать – одна десятая секунды.

  • 0.1 секунды – подходящее время для вибрации в ответ на нажатие кнопки (и самое меньшее время вибрации вообще).
  • 2 секунды – «ЧТО ПРОИСХОДИ С МОИМ ТЕЛЕФОНОМ???». Две секунды – слишком большое время для почти любого единичного оповещения.
  • 300 миллисекунд – подводящее время для единичного оповещения. Оно привлекает внимание пользователя, не заставляя его думать, что с телефоном что-то не так.
  • Быстрая пульсация, ещё один походящий способ сообщить что-то пользователю. Пример такой пульсации Вы можете скачать ниже.

Пример кода.