Работа с датчиками, определение местоположения
Цель работы: освоить методы работы со встроенными датчиками
Встроенные датчики
При разработке для Windows Phone можно использовать показания встроенных датчиков устройства, сведения о них можно найти в обзорном материале по пространству имен Windows.Devices.Sensors (http://msdn.microsoft.com/en-us/library/windowsphone/develop/br206408.aspx). Один из доступных датчиков – акселерометр, он позволяет организовывать управление программами путем перемещения телефона в пространстве.
При работе с акселерометром данные, которые можно от него получить, представляют сведения об ускорении устройства в гравитационных единицах. Например, (1,0,0). Если сопоставить эти данные с телефоном, то, если расположить телефон кнопками, расположенными под экраном, вниз, лицевой стороной к наблюдателю, окажется, что ось Y проходит вдоль длинной стороны экрана (положительное направление оси – вверх), X – вдоль короткой (положительное направление оси – вправо), ось Z располагается перпендикулярно экрану (положительное направление – в сторону наблюдателя). Это остаётся справедливым и при поворотах телефона.
Когда телефон неподвижен, акселерометр, регистрирует силу земного притяжения, что отражается в его показаниях (они, по соответствующей оси, близки к 1), перемещения телефона в пространстве приводят к изменению показаний.
Таким образом, оказывается, например, если телефон лежит на горизонтальной поверхности неподвижно, экраном вверх, показания акселерометра выглядят как (0, 0, -1). Если расположить телефон вертикально, кнопками вниз, мы имеем в показаниях (0, -1, 0), перевернув телефон "вверх ногами" – (0, 1, 0). Если повернуть телефон на 90° против часовой стрелки – мы получим (-1,0,0). Акселерометр очень чувствителен, даже при неподвижном устройстве показания не бывают в точности равными идеальным, к тому же, они колеблются в небольших пределах.
В демонстрационном проекте P16_1, на странице AccPage.xaml показана работа с акселерометром. В этом примере мы, кроме того, рассматриваем использование карты и работу с сервисом определения местоположения (этот пример основан на примере Simple Map control sample, скачать пример в исходном виде можно здесь: http://code.msdn.microsoft.com/wpapps/Simple-Map-control-sample-fc94908f). На рис. 47.1. показан состав проекта и страница настройки возможностей в редакторе манифеста приложения. Обратите внимание на то, что включены возможности ID_CAP_LOCATION и ID_CAP_MAP – в противном случае приложение работать не будет.
увеличить изображение
Рис. 47.1. Проект, демонстрирующий работу акселерометра и службы определения местоположения
На странице находятся три текстовых блока, мы перемещаем их в плоскости страницы в соответствии с данными об ускорении по осям X и Y, при этом выводим в соответствующих полях сведения об ускорении. В одном из полей мы выводим данные по оси Z, при этом мы не используем для управления объектами эти данные. В Листинге 24.1 вы можете видеть код файла AccPage.xaml.cs. Обратите внимание на то, что код здесь максимально упрощён, в реальном приложении, использующем акселерометр, нужно позаботиться о дополнительных механизмах, в частности, об обработке ошибок.
using System; using Microsoft.Phone.Controls; using Microsoft.Devices.Sensors; using System.Windows.Media; namespace P16_1 { public partial class AccPage : PhoneApplicationPage { //Для акселерометра private Accelerometer accelerometer; //Для трансформации private TranslateTransform moveTranslation; public AccPage() { InitializeComponent(); //Новый экземпляр объекта Accelerometer accelerometer = new Accelerometer(); //Время между обновлениями показаний акселерометра accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20); //Подключаем обработчик события, возникающего при получении новых данных accelerometer.CurrentValueChanged += new System.EventHandler<SensorReadingEventArgs<AccelerometerReading>> (accelerometer_CurrentValueChanged); //Запуск акселерометра accelerometer.Start(); //Новая трансформация moveTranslation = new TranslateTransform(); //Назначаем трансформацию текстовым блокам txtX.RenderTransform = this.moveTranslation; txtY.RenderTransform = this.moveTranslation; txtZ.RenderTransform = this.moveTranslation; } //Обработчик void accelerometer_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerReading> e) { //Вызов метода, который работает с объектами в потоке пользовательского интерфейса Dispatcher.BeginInvoke(() => MoveObject(e.SensorReading)); } //Метод для перемещения объекта void MoveObject(AccelerometerReading accData) { //Задаем текст для вывода в текстовые блоки txtX.Text = "X=" + accData.Acceleration.X.ToString(); txtY.Text = "Y=" + accData.Acceleration.Y.ToString(); txtZ.Text = "Z=" + accData.Acceleration.Z.ToString(); //Перемещаем блоки на плоскости moveTranslation.X += accData.Acceleration.X * 2; moveTranslation.Y -= accData.Acceleration.Y * 2; //Задаём границы области, которые не могут пересечь перемещаемые объекты if (moveTranslation.X <= 0) { moveTranslation.X = 0; } if (moveTranslation.Y <= 0) { moveTranslation.Y = 0; } if (moveTranslation.X >= 300) { moveTranslation.X = 300; } if (moveTranslation.Y >= 550) { moveTranslation.Y = 550; } } } }Листинг 47.1. Код файла AccPage.xaml.cs
Обратите внимание на обработчик accelerometer_CurrentValueChanged. Этот обработчик выполняется в собственном потоке, а пользовательский интерфейс – в собственном. В итоге, для того, чтобы обратиться к элементу пользовательского интерфейса, нам понадобится воспользоваться диспетчером (Dispatcher), с помощью которого можно направить задание из одного потока в другой. В данном случае мы используем лямбда-выражение.