Мобильная ОС Windows Phone 7.5 обладает колоссальным набором функций, к которым можно получить доступ с помощью SDK 7.1. Посвящать рассмотрению каждой из них целую статью было бы неразумно, поэтому мы решили построить статью как сборник рецептов — небольших очерков о каждой интересной функции.

Весной Microsoft выпустила очередное обновление для средств разработки под свою мобильную платформу. Особо продвинутых фич этот апгрейд не добавил, разве что в эмуляторе появилась поддержка тестирования приложений для малобюджетных устройств с 256 Мб оперативы. Также апгрейд обновил старый эмулятор — для устройств с 512 Мб. В этой статье я буду описывать работу с обновленными средствами разработки.

Для начала вспомним, что смартфон на базе Windows Phone обязан обладать определенным набором устройств, иначе он не будет сертифицирован Microsoft как устройство для Windows Phone. К некоторым устройствам программист имеет доступ через API, но, к сожалению, пока еще не ко всем. Хотя при использовании SDK прошлой версии (7.0) у программиста было еще меньше возможностей. В этой статье мы рассмотрим несколько рецептов для работы с «открытыми» для использования девайсами.

 

Рецепт 1. Вибровызов

Это самый простой трюк, который можно осуществить через доступ к харду смартфона. Итак, приступим. Запусти Visual Studio 2010, создай новый проект Windows Phone Application на базе Silverlight. Размести на заготовке приложения две кнопки. Создай обработчики нажатия для обеих. В первом из них напиши:

VibrateController.Default.Start(TimeSpan.FromSeconds(5));

С помощью этой строчки кода ты запустишь виброзвонок продолжительностью пять секунд. Если необходимо завершить вызов досрочно, то надо просто вызватьVibrateController.Default.Stop();

Это будет происходить при нажатии второй копки, в обработчик которой нAPIши приведенную инструкцию. Не забудь приинклудить пространство имен Microsoft.Devices;

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

 

Рецепт 2. Использование радио

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

 FMRadio myRadio = FMRadio.Instance;
 myRadio.CurrentRegion = RadioRegion.Europe;
 myRadio.Frequency = 103.9; // не подумай, что я слушаю это, просто для теста :)
 myRadio.PowerMode = RadioPowerMode.On;

В первой строке получаем экземпляр класса FMRadio и сохраняем его в переменной. Затем устанавливаем регион нашего пребывания, их всего три: Europe, Japan и United States. Выбираем ближайший :). Далее надо установить желаемую частоту. Финальным аккордом включаем радио. Не забудь подключить к телефону (ты же на реальном девайсе дебажишь?) наушники, поскольку Windows Phone запускает радио, только если они подсоединены. Чтобы выключить радио, достаточно написать: myRadio.PowerMode = RadioPowerMode.Off;Можно и просто выдернуть наушники, и радио автоматом выключится.

 

Рецепт 3. Положение телефона в пространстве

В каждом смартфоне на базе Windows Phone имеется девайс, именуемый акселерометром. Он позволяет узнать положение телефона в пространстве.Другими словами, он определяет силу, применимую к телефону в направлении каждой из трех осей (в диапазоне от –1 до 1), то есть насколько телефон наклонен в ту или иную сторону. На практике данные от акселерометра применяются для определения способа взаимодействия с телефоном (трясет его владелец или перемещает), что может использоваться, например, в играх для создания особого типа контрола. Напишем небольшую прогу, которая, учитывая наклон смартфона, будет выводить позицию устройства, что, как мы выяснили выше, соответствует уровню силы, применяемой к телефону.

Размести на заготовке три надписи — для данных каждой из осей и две кнопки — для запуска и остановки считывания с акселерометра данных. Чтобы работать с сенсорными устройствами — если кто спросит, акселерометр является одним из них :), — добавь в проект две сборки: Microsoft.Xna.Framework и Microsoft.Device.Sensors (Project -> Add Reference). В начале файла C# кода добавь ссылки на следующие пространства имен: Microsoft.Xna.Framework, Microsoft.Devices.Sensors.

Чтобы начать работу с акселерометром, надо объявить и создать устройство. В начале класса MainPage напиши: Accelerometer Acc = new Accelerometer();

Теперь надо зарегистрировать обработчик события изменения положения телефона. Для этого в конструкторе класса напиши: Acc.CurrentValueChanged += Acc_CurrentValueChanged;

Также в конструкторе надо для вновь созданного устройства задать значение свойстваTimeBetweenUpdates — оно отвечает за временной период, через который будет возбуждаться событие: Acc.TimeBetweenUpdates = TimeSpan.FromMilliseconds(100);

Наконец, напишем обработчик уже зарегистрированного события:

 void Acc_CurrentValueChanged(object sender,
SensorReadingEventArgs<AccelerometerReading> e)
  {
   var position = e.SensorReading.Acceleration;
   Dispatcher.BeginInvoke(() =>
   {
xpos.Text = position.X.ToString("0.0");
ypos.Text = position.Y.ToString("0.0");
zpos.Text = position.Z.ToString("0.0");
   });
  }

В начале тела функции объявляем переменную position неявного типа, который станет известным после присваивания значения; его мы тут же присваиваем, считывая значение с акселерометра. Считанные данные являются типом Vector3.

Следующим действием запускается новый поток для работы с пользовательским интерфейсом (ключевое слово Dispatcher). Вообще, многопоточную концепцию Silverlight можно разделить на два типа: для работы с пользовательским интерфейсом и всю остальную. К первому как раз относится класс Dispatcher, а ко второму — BackgroundWorker. Подробнее о потоках Silverlight ты можешь узнать на сайте Microsoft (там имеется очень подробная документация), как говорится — Bing тебе в помощь :), а мы рассматриваем кодирование для Windows Phone. Собственно, BeginInvoke запускает асинхронный поток, в котором трем текстовым меткам присваиваются координаты по трем осям, преобразованные к текстовому виду.

Если для эксперимента ты закомментишь строку создания и начала выполнения потока (после того, как дочитаешь рецепт), то в таком случае получишь исключение неавторизированного доступа, связанное с невозможностью обновить элементы пользовательского интерфейса из потока, не являющимся порожденным от класса Dispatcher (та проблема, которую мы с тобой обсуждали выше). Последним штрихом нашей программы будут обработчики событий нажатия кнопок, в результате выполнения которых в первом случае акселерометр запустится, а во втором — прекратит передавать данные.

Для первой кнопки напиши: Acc.Start();

И для второй: Acc.Stop();

Если у тебя нет устройства, ты все же можешь протестировать этот трюк, воспользовавшись расширенными средствами эмулятора (рис. 1).

Рис. 1. Тестирование акселерометра на эмуляторе
Рис. 1. Тестирование акселерометра на эмуляторе
 

Рецепт 4. Работа с компасом

Для компаса можно сделать продвинутый интерфейс, подобный настоящему прибору, но мы сейчас в этом не заинтересованы, поскольку для начала логичнее всего будет разобраться в программном интерфейсе компаса. Для нового приложения создай пользовательский интерфейс в виде текстовой метки и двух кнопок. Файл с C# кодом можешь скопировать из прошлого проекта, заменяя названия в соответствии с новым решением. Вместо объекта класса Accelerometer создай объект класса Compass. В обработчиках кнопок запускай и останавливай новый объект компаса. Более всего изменился обработчик события CurrentValueChanged:

 void comp_CurrentValueChanged(object sender,
   SensorReadingEventArgs<CompassReading> e) 
  {
   var position = e.SensorReading.MagneticHeading;
   Dispatcher.BeginInvoke(() =>
   {
   xpos.Text = position.ToString();  
   });
  }

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

 

Особенности средств хранения данных в windows phone 7.5

Рецепты с пятого по седьмой касаются средств хранения данных. Как я рассказывал в прошлой статье, посвященной безопасности Windows Phone (см. мартовский номер «Хакера»), чтобы поддерживать наивысший уровень безопасности, эта ОС имеет ограниченный набор средств для работы с хранилищем информации, по сравнению, например, с ОС для десктопов. То есть определенное приложение имеет доступ не ко всей флеш-памяти, а только к своему локальному хранилищу. Для законных приложений этого более чем достаточно, зато в этом механизме для разработчика приготовлены приятные плюшки, делающие взаимодействие с хранилищем удобнее. Так как мы в прошлой статье рассмотрели сохранение двоичных — плоских файлов, то здесь посмотрим на способы хранения структурированных файлов.

 

Рецепт 5. XML

Текстовый формат XML настолько распространен, что было бы странно, если бы в Windows Phone не было его поддержки. Здесь имеется поддержка, пришедшая в телефон вместе с .NET. Кроме того, до выхода версии 7.5 XML-документы являлись единственным способом создания баз данных. Но о базах данных мы поговорим позднее, а сейчас обратим внимание на XML.

Уверен, не стоит в очередной раз говорить о том, что такое XML, поэтому сразу перейдем к программингу.

Для тестирования рецепта напишем маленькую прогу, с помощью которой пользователь будет вводить какие-то данные, сохранять в телефоне, а затем при следующем запуске восстанавливать эти данные из изолированного хранилища, в котором с прошлого сеанса работы они будут храниться в структурированном файле. Пускай эти данные будут представлены тремя строками — соответственно, имя, фамилия, ник.

Первым действием добавь в проект две сборки System.Xml и System.Xml.Serialization. Затем добавь ссылки на четыре пространства имен: System.IO, System.IO.IsolatedStorage, System.Xml, System.Xml.Serialization.

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

 public class UserData
  {
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string NickName { get; set; }
  }

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

  var record = new UserData();
   record.FirstName = textBox1.Text;
   record.NickName = textBox3.Text;
   record.LastName = textBox2.Text;
   using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   using (var file = store.CreateFile("data.xml")) // создаем файл для сохранения
   {
   XmlSerializer ser = new XmlSerializer(typeof(UserData)); // объявляем переменную для 
   ser.Serialize(file, record);  // сериализации экземпляра класса UserData
   }

Процесс сериализации состоит из четырех шагов:

  1. Получить объект хранилища, который будет использоваться на протяжении всей операции записи.
  2. Создать в хранилище XML-файл для записи.
  3. Преобразовать поля экземпляра класса в последовательность битов, подходящую для записи во флеш-память.
  4. Наконец, сбросить данные в энергонезависимую память.

Использование конструкции с ключевым словом using, независимо от успеха или неудачного выполнения операции, гарантирует освобождение выделенной под обрабатываемые объекты памяти. То есть освобождение памяти обязательно происходит при выходе потока выполнения за скобки конструкции. Это может происходить только с объектами, порожденными от класса, наследующего интерфейс IDisposable. Потому что использование этой конструкции предполагает вызов в ее конце метода Dispose объекта.

Далее напишем код для обработчика нажатия второй кнопки:

 UserData record = null;
   using (var store = IsolatedStorageFile.GetUserStoreForApplication())
   using (var file = store.OpenFile("data.xml", FileMode.Open))
   {
   XmlSerializer ser = new XmlSerializer(typeof(UserData));
   var reader = XmlReader.Create(file);
   if (ser.CanDeserialize(reader))
   {
record = (UserData)ser.Deserialize(reader);
textBox1.Text = record.FirstName;
textBox2.Text = record.LastName;
textBox3.Text = record.NickName;
   }
   } 

Здесь все аналогично: создаем переменную нашего класса для последующего сохранения значений, получаем объект хранилища, для чтения открываем файл data.xml, для предстоящей десериализации создаем объект, проверяем, можно ли читать заданный файл. Если результат положительный, тогда десериализуем содержимое открытого файла, таким образом преобразуем считанные данные в значения полей класса, последним действием присваиваем свойству Text текстовых полей пользовательского интерфейса значения полей класса.

Теперь можешь проверить результат. К сожалению, только на реальном аппарате — эмулятор не подойдет. После закрытия эмулятора данные в его виртуальном хранилище будут удалены, а после нового запуска и попытки восстановить сохраненные данные тебя будет ждать исключение.

 

Рецепт 6. JSON

JSON (JavaScript Object Notation) — более компактный, чем XML, текстовый формат для описания структурированных данных, поэтому он все шире задействуется в информационных системах, в том числе на мобильных девайсах. Изначально этот формат применялся вместе с JavaScript (что следует из названия), однако сейчас используется со многими другими языками. Объект JSON гораздо лаконичнее, чем объект XML, — приведу пример объекта, содержащего данные экземпляра класса UserData:

{ “FirstName” : “Yuriy”, “LastName” : “Yazev”, “NickName” : “yurembo” }
Такой формат гораздо проще для чтения, чем даже XML :). 

Напишем пример: реализуем сериализацию объектов нашего класса в формат JSON. У нового приложения пользовательский интерфейс сделай таким же, как и в предыдущем проекте, также скопируй класс UserData. Чтобы воспользоваться функциональностью класса DataContractJsonSerializer, содержащего средства JSON-сериализации, необходимо добавить в проект сборку SystemServicemodel.Web, а затем добавить ссылки на три пространства имен: System.IO, System.IO.IsolatedStorage, System.Runtime.Serialization.Json. Не считаю нужным полностью приводить код обработчиков событий. В них код более-менее понятен, скопируй его из прошлого проекта. Расскажу о правке кода на пальцах :). Во-первых, в функции сохранения и восстановления данных создай файл с расширением json вместо расширения xml. Это вовсе не обязательно, но с эстетической точки зрения считается более чистым. Во-вторых, для сериализации и десериализации данных вместо объекта класса XmlSerializer воспользуйся объектом класса DataContractJsonSerializer. В-третьих, для сброса данных в память заюзай метод WriteObject вместо метода Serialize. И наконец, в-четвертых, для чтения файла из хранилища воспользуйся методом ReadObject вместо Deserialize. Теперь протестируй приложение (аналогично тестированию прошлого рецепта). На вид работает так же, но теперь используется другой способ сериализации/десериализации информации.

 

Рецепт 7. База данных в твоем телефоне

В позапрошлом рецепте я обещал рассказать о поддержке баз данных в Windows Phone 7.5, настала пора под занавес статьи выполнить обещание. Вообще, базы данных представляют собой настолько полезный и удобный способ хранения информации, что я был удивлен отсутствием их поддержки в прошлой версии мобильной ОС от одного из основных вендоров СУБД — Microsoft. Как я упомянул ранее, в то время разработчики для хранения структурированных данных использовали файлы XML-формата, при этом они сильно ругались, но выбора не было. Такое положение дел не могло продолжаться долго, и в текущую версию Windows Phone Microsoft добавила поддержку БД SQL Server Compact. Теперь стало возможным хранить структурированные данные в специально предназначенном для них формате — базах данных. Однако в этой на первый взгляд прекрасной бочке меда есть пара ложек дегтя. Компактная версия SQL Server для работы с данными не поддерживает ни Transact-SQL, ни ADO.NET. Зато есть LINQ. Хотя я с довольно большим энтузиазмом встречаю новые разработки Microsoft, изначально к LINQ у меня было противоположное отношение. Зачем надо было переворачивать SQL с ног на голову? Попытка исправить его? Конечно, SQL тоже не идеальная технология, и первоначально (в 70-е годы прошлого века) он разрабатывался не для программистов, но к нему уже все привыкли. Ладно, это уже философский вопрос (поэтому нас, программистов, он так волнует :)), оставим его обсуждение на потом. Перейдем к SQL Server Compact: что имеем, то имеем.

Из-за того что новый пример достаточно объемный, я не буду приводить все листинги в журнале. Я буду давать краткие рекомендации к коду, а сам исходник ты сможешь взять с диска. В качестве примера давай разработаем программу, которая ведет учет пользователей в БД гипотетической MMOg. Таким образом, БД в нашем случае будет состоять из двух таблиц: в первой содержится информация о человеке, которую этот человек ввел при регистрации, а во второй — данные его персонажа. В начале работы над новым проектом добавь в него сборку System.Data.Linq, предназначенную для взаимодействия с данными посредством языка LINQ. Начнем с создания БД. Эту процедуру можно провести как минимум тремя способами: описать все классы данных руками, поручить эту работу Visual Studio и заблаговременно создать БД, а потом залить ее в телефон вместе с XAP-файлом и развернуть ее там вместе с приложением. Ясно, что первый вариант профнепригоден, а третий недостаточно гибок, к тому же в таком случае БД получается только для чтения. Конечно, можно сделать ее модифицируемой, но зачем нам дополнительные манипуляции, если можно воспользоваться вполне удобным вторым способом и создать БД визуальными средствами? Выбери в главном меню «Tools» пункт «Connect to Database». Откроется окно выбора источника данных, выбери «Microsoft SQL Server Compact 3.5», затем появится окно «Add Connection». В разделе «Connection Properties» в поле «Database» введи имя базы данных вместе с путем к файлу и расширением sdf (рис. 2).

Рис. 2. Создание БД
Рис. 2. Создание БД

После нажатия кнопки «Create» будет предложено задать пароль для доступа к БД, а также выбрать режим шифрования. Далее, нажимая кнопки «ОK», закрой оба окна. В результате новая пустая БД будет создана в заданной папке, а в Server Explorer будет добавлен новый элемент — БД. Чтобы создать таблицу, разверни БД и в контекстном меню подпункта «Tables» выбери пункт «Create Table». В открывшемся окне задай имя таблицы и введи данные для полей (рис. 3).

Рис. 3. Создание таблицы Users
Рис. 3. Создание таблицы Users

Таким же путем создай еще одну таблицу (рис. 4).

Рис. 4. Создание таблицы Players
Рис. 4. Создание таблицы Players

Зададим отношение между таблицами, пускай оно будет один к одному по полям ID, то есть одному пользователю соответствует один персонаж. В Server Explorer из контекстного меню для элемента — таблицы Players выбери «Table Properties». В открывшемся окне по указателю в левой части перейди на вкладку «Add Relations», в поле «Relation Name» введи имя для отношения (например, ID_REL), в выпадающем списке «Primary Key Table» выбери главную таблицу (Users), список «Foreign Key Table» должен быть неактивен, по умолчанию в нем выбрана таблица Players. В списках «Foreign Key Table Column» и «Foreign Key Table Column» должны быть выбраны поля ID. После этого нажми кнопку «Add Columns», затем ниже кнопку «Add Relation». Появится окно с сообщением об успешном создании отношения. Жми ОK в нем и в окне табличных свойств.

Теперь, когда у тебя есть созданная SQL Server Compact БД, надо создать файл с классами, описывающими ее таблицы, поля таблиц и другие свойства. Это можно выполнить с помощью инструмента командной строки: «Пуск -> Все программы-> Microsoft Visual Studio -> Visual Studio Tools -> Visual Studio Command Prompt (2010)». Перейди в каталог с БД: cd C:\DB, затем выполни такую команду:

sqlmetal gameDB.sdf /code:gameDB.cs /pluralize

В результате будет создан желаемый файл, однако если будут предупреждения, то их надо править, модифицируя структуру БД в Visual Studio. Следующим действием добавим этот файл в проект. В VS в Solution Explorer, щелкнув правой клавишей на проекте, из контекстного меню выбери «Add -> Existing Item». В диалоге найди созданный на прошлом шаге файл (gameDB.cs). Теперь добавь в заготовку кнопку и в обработчике события ее нажатия напиши код для создания БД:

 using (var db = new GameDB(DBStr))
   {
   if (db.DatabaseExists() == false) // если БД не существует,
   {
db.CreateDatabase(); // то создать
   }
   } 

Не забудь в начало класса поместить объявление пути к БД: string DBStr = "Data Source=isostore:/gameDB.sdf";. Теперь попробуй скомпилировать проект. Появятся две ошибки, связанные с использованием в двух из трех конструкторов нашего класса GameDB необъявленного интерфейса IDbConnection. Нам эти конструкторы не нужны, поэтому смело удаляй оба. Теперь добавим функциональность, позволяющую добавлять данные в БД и извлекать из нее. Поскольку мы жестко ограничены в размерах области пользовательского интерфейса, то для ввода и вывода данных будут служить шесть текстовых полей (TextBox), так как в общей сложности имеем в таблицах шесть полей с «полезными» данными. Ну, это же лишь пример работы с мобильной БД. После размещения текстовых полей добавь еще две кнопки, нажатие одной из которых (Get Data) будет возвращать данные из обеих таблиц, относящиеся к заданному пользователем идентификатору, нажатие второй (Insert Data) будет заносить в обе таблицы введенные пользователем данные. Я не буду приводить здесь код обработчиков событий их нажатий — смотри исходник на диске, здесь я лишь замечу: выборка производится по идентификатору, который обязательно уникальный (первичный ключ) и одинаковый в обеих таблицах (внешний ключ для таблицы Players), а для создания записи создается объект класса определенной таблицы, его поля заполняются значениями для полей таблицы, после этот объект участвует в обновлении таблицы, в конце функции вызывается метод для применения обновлений к БД. На этом минимум действий, необходимый для работы программы, завершен, проверь ее на устройстве или эмуляторе, все работает так, как планировали. Совет: при вставке данных их лучше проверять на корректность значений или хотя бы поместить блок кода в конструкцию try/catch.

Приложение для работы с БД
Приложение для работы с БД

 

WWW

www.microsoft.com — на этом сайте находится много интересной документации о Windows Phone и сопутствующих технологиях.

 

Выводы

В статье мы рассмотрели два типа рецептов кодинга для смартфонов на базе ОС Windows Phone: первые четыре рецепта посвящены работе со встроенными девайсами средствами SDK 7.1, последние три трюка показали, как хранить, загружать и обрабатывать структурированные данные. Однако, посмотрев на то, что мы сегодня сделали, я решил, что сделали мы все отлично :). Смущает разве что простейший интерфейс написанного. А ведь современный пользователь смартфона обращает на него внимание в первую очередь! Поэтому — не расслабляйся, в следующем номере тебя будет ждать новая порция рецептов, посвященная этой теме. До встречи!

 

Оставить мнение

Check Also

Как Apple обходит стандарты, заставляя тебя платить. Колонка Олега Афонина

Иногда сложные вещи начинаются с простых: планшет iPad Pro 10.5 вдруг перестал заряжаться …