Silverlight 5, XAML и связывание данных
В рамках on-line части конференции DevCon’11 я зыписал доклад Silverlight 5, XAML и связывание данных.
В рамках on-line части конференции DevCon’11 я зыписал доклад Silverlight 5, XAML и связывание данных.
<< День #23. Реклама в WP7 приложениях.
Это двадцать четвёртая статья серии «45 дней с Windows Phone 7».
В Дне #18 мы подробно рассматривали возможности элемента управления «WebBrowser». После этого мне было задано достаточно много вопросов, преимущественно о том, как загружать локальные ресурсы, в первую очередь картинки, в данный элемент управления. Если картинка находится на удалённом web сервере, то проблем нет. Мы просто пишем её Url адрес. Но что делать, если картинка находится в ресурсах приложения? Ведь метод «NavigateToString» браузера не позволяет задать местоположение, загружаемых ресурсов.
На помощь нам приходит изолированное хранилище. Мы уже рассматривали данную тему в Дне #15. В изолированное хранилище можно положить HTML страницы и ресурсы к ним, такие как картинки, а после этого отобразить данные страницы в элементе управления «WebBrowser».
Создадим новое приложение и разместим на главной странице элемент управления «WebBrowser» с именем «webBrowser1». Подпишемся на событие «Loaded» созданного элемента управления. Но перед тем как создать обработчик события, добавим функцию сохранения текстовых файлов в изолированном хранилище:
private static void SaveToIsoStore(string fileName, string text)
{
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
if (isoStore.FileExists(fileName))
isoStore.DeleteFile(fileName);
using (var sw = new StreamWriter(isoStore.CreateFile(fileName)))
{
sw.Write(text);
}
}
Данная функция принимает имя и содержимое файла, который потом создаётся в изолированном хранилище.
Теперь с помощью данной функции создадим файл «fileName123.htm» и отобразим его в элементе управления «WebBrowser»:
private void WebBrowser1Loaded(object sender, RoutedEventArgs e)
{
SaveToIsoStore("fileName123.htm", "<h1>Isolated Storage!!!</h1>");
webBrowser1.Navigate(new Uri("fileName123.htm", UriKind.Relative));
}
Всё верно, мы можем просто передать имя файла относительно корня изолированного хранилища элементу управления «WebBrowser».
К сожалению, мы не можем также легко передать браузеру имя файла из ресурсов приложения, как это было в случае с файлами в изолированном хранилище. Поэтому вначале нам требуется сохранить файл из ресурсов в изолированном хранилище.
Добавим в проект два файла: «readme.htm» и «windows-phone-7.jpg» и установим свойство «Build Action» для файлов в значение «Content».
Файл «readme.htm» – это просто html страница, на которой находится картинка «windows-phone-7.jpg»:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head> <title>Untitled Page</title> </head> <body> <h2>Windows Phone 7!</h2> <h3>Замечательная ОС</h3> <img src="windows-phone-7.jpg" /> </body> </html>
Теперь создадим функцию сохранения в изолированном хранилище любого файла, а не только текстового, как это было в первом примере:
private static void SaveToIsoStore(string fileName, byte[] data)
{
var strBaseDir = string.Empty;
const string delimStr = "/";
var delimiter = delimStr.ToCharArray();
var dirsPath = fileName.Split(delimiter);
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
for (var i = 0; i < dirsPath.Length - 1; i++)
{
strBaseDir = Path.Combine(strBaseDir, dirsPath[i]);
isoStore.CreateDirectory(strBaseDir);
}
if (isoStore.FileExists(fileName))
{
isoStore.DeleteFile(fileName);
}
using (var bw = new BinaryWriter(isoStore.CreateFile(fileName)))
{
bw.Write(data);
bw.Close();
}
}
Воспользуемся данной функцией и сохраним нужные нам файлы из ресурсов приложения. Кроме того, после сохранения файлов, перейдём в браузере на только что сохранённую страницу «readme.htm»:
private void WebBrowser1Loaded(object sender, RoutedEventArgs e)
{
string[] files = {
"readme.htm",
"windows-phone-7.jpg"
};
foreach (var f in files)
{
var sr = Application.GetResourceStream(new Uri(f, UriKind.Relative));
using (var br = new BinaryReader(sr.Stream))
{
var data = br.ReadBytes((int)sr.Stream.Length);
SaveToIsoStore(f, data);
}
}
webBrowser1.Navigate(new Uri("readme.htm", UriKind.Relative));
}
Запустим приложение и увидим страницу с находящейся на ней картинкой:

Примите во внимание, что в реальном приложении не стоит каждый раз при загрузке сохранять файлы из ресурсов в изолированное хранилище. Код требует оптимизации.
<< День #22. Trial (пробная) версия приложения.| День #24. WebBrowser. Часть 2. Локальный контент. >>
Это двадцать третья статья серии «45 дней с Windows Phone 7».
В предыдущей статье мы говорили о том, как сделать пробную (trial) версию Windows Phone 7 приложения. Эта версия, по сути, предназначена для того, чтобы приложение лучше продавалось. Сегодня мы узнаем, как можно заработать, даже создавая бесплатные приложения. А если говорить более конкретно, рассмотри, как можно добавить в приложения рекламу с помощью Microsoft Advertising SDK for Windows Phone 7.
Примите во внимание, что вывод денег, полученных от рекламы в Россию недоступен. Требуется искать обходные пути. Здесь ситуация почти как с PayPal.
В первую очередь стоит посетить Microsoft Advertising pubCenter. На данном сайте описана последовательность шагов, необходимых для показа рекламы в Ваших приложениях: получение SDK, регистрация приложения, добавление рекламных элементов управления на страницы.
Так как данная серия ориентирована на разработчиков, здесь мы также рассмотрим работу с элементом управления «AdControl», служащим для показа рекламы.
Для начала Advertising SDK, в состав которого входит нужный нам элемент управления, требуется скачать и установить. Если Вы не читали предыдущий параграф и поэтому не посещали Microsoft Advertising pubCenter, то можете скачать SDK напрямую:
http://www.microsoft.com/downloads/en/details.aspx?FamilyID=b0f00afc-9709-4cc2-ba2c-57728db6cbd6
Установив SDK, добавим элемент управления «AdControl» на Toolbox в Visual Studio, как мы это делали с элементом управления «Panorama» в Дне #16.
Теперь разместим элемент управления на главной странице нашего приложения:
<ad:AdControl AdUnitId="Image480_80" ApplicationId="test_client" />
Нам требуется задать два обязательных свойства: AdUnitId и ApplicationId. Значения обоих свойств можно получить, зарегистрировав приложение в Microsoft Advertising pubCenter, создав там новый Ad Unit (рекламную единицу) и задав все необходимые настройки.

При разработке и тестировании приложений, содержащих рекламу, не стоит использовать настоящие значения AdUnitId и ApplicationId. Поскольку это будет выглядеть как нелегальное накручивания себе количества кликов и показов. Кроме того, «AdControl» может распознать, когда работает в эмуляторе, и не будет показывать настоящую рекламу в этом случае.
Далее я приведу тестовые значения, которые стоит использовать при отладке:
| Ad Type | Ad Model | Size (WxH) | Test ApplicationId | Test AdUnitId |
| Text Ad | Contextual | 480 x 80 | test_client | TextAd |
| XXL Image Banner | Contextual | 480 x 80 | test_client | Image480_80 |
| XL Image Banner | Contextual | 300 x 50 | test_client | Image300_50 |
В примере выше я использовал «Image480_80» баннер, который, как нетрудно догадаться из названия, будет занимать на экране область размером 480 на 80 пикселей.
Рекламные единицы (ad units) задают основные настройки рекламы. В том числе ту категорию рекламных объявлений, которая будет показываться. Допустим, мы создаём приложение «Таймер чистки зубов». Данное приложение поможет детям определить, сколько времени чистить каждую область рта. Поскольку родители тоже, скорее всего, захотят посмотреть, сколько их ребёнок чистит зубы, реклама в данном приложении будет в самый раз. Но не показывать же в этот момент рекламу, связанную с программированием на C++??? Требуется что-то более подходящее.
Для каждой рекламной единицы мы можем определить категории рекламных объявлений. Категорий достаточно много (примерно 385) и Вы можете выбрать несколько из них, но не более трёх. Вот как выглядит список категорий:
Для нашего приложения, помогающего чистить зубы, мы выберем, в том числе категорию «Health & Fitness – Dental Care».
После создания рекламной единицы, скопируем значения «AdUnitId» и «ApplicationId» в pubCenter, и зададим их в нашем элементе управления. Код будет выглядеть примерно так:
<ad:AdControl x:Name="AdBox" AdUnitId="10018171" ApplicationId="350b8257-d92a-4978-a218-f3650bd485df" Margin="-12,528,-12,0" Width="480" Height="80" />
А так будет выглядеть приложение, запущенное в эмуляторе:

Просто добавив рекламный элемент управления в приложение (предположим, что приложение используется реальными людьми), Вы начнёте замечать активность в pubCenter. Кроме того, в pubCenter можно найти несколько метрик, самой главной из которых для Вас является, конечно же, «Revenue» – доход.
Надо отметить, что есть интересный способ монетизации приложений. В дне #22 мы рассматривали, как сделать пробную версию приложения, но пробная версия не обязательно должна иметь урезанную функциональность. Она может быть полнофункциональной, просто в ней будет показываться реклама. Если пользователь заплатит деньги за приложение – реклама показываться перестанет. Данная модель относительно популярна.
<< День #21. Приложения и игры.| День #23. Реклама в WP7 приложениях. >>
Это двадцать вторая статья серии «45 дней с Windows Phone 7».
Вчера мы говорили о том, как добавить приложение (игру) в хаб «Games». Сегодня мы узнаем, как сделать триальную (Trial) – пробную версию приложения или игры. На самом деле это не какая-то специализированная версия (.xap файл будет тот же), а просто некоторые дополнительные проверки в коде, благодаря которым в процессе работы приложение может изменять функциональность в зависимости от того, в каком режиме работает: полном или пробном. При покупке приложения в Marketplace, пользователь имеет возможность сначала приложение попробовать, а если оно ему понравится – уже заплатить деньги и использовать полную версию.

Иллюстрация с сайта pocketgamer.co.uk
На иллюстрации процесса покупки видно, что внизу экрана присутствуют две кнопки – попробовать (try) и купить (buy). Типичным примером использования данной функциональности являются игры. Допустим, игра имеет 50 уровней. Тогда разработчик может в пробной версии оставить возможность пройти игру только до 5-ого уровня, а для прохождения остальных будет требоваться покупка игры.
В пространстве имён «Microsoft.Phone.Marketplace» есть, в том числе класс «LicenseInformation», который позволяет получить информацию о текущем статусе оплаты нашего приложения. Подключим нужное пространство имён:
using Microsoft.Phone.Marketplace;
Следующим шагом будет создание экземпляра класса «LicenseInformation»:
var li = new LicenseInformation();
Это почти всё, что требуется сделать. Класс «LicenseInformation» содержит функцию «IsTrial», возвращающую булевское значение и позволяющую определить, работаем ли мы в пробном режиме:
if (!li.IsTrial())
{
//Сделать что-то, доступное только платным пользователям
}
else
{
//Сделать что-то, доступное пробным пользователям
}
К сожалению, нет никакого встроенного способа переключения между пробным и полным режимами при разработке приложения («IsTrial()» на эмуляторе возвращает false). Но я использую достаточно простой способ, чтобы иметь возможность отлаживать пробную версию. Для этого я проверяю, находимся ли мы в режиме отладки, и если да, то сохраняю в настройках приложения параметр «trialMode» в значении «true». Делается это в файле «App.xaml.cs»:
IsolatedStorageSettings _settings = IsolatedStorageSettings.ApplicationSettings;
public App()
{
UnhandledException += Application_UnhandledException;
_settings["trialMode"] = false;
if (System.Diagnostics.Debugger.IsAttached)
{
_settings["trialMode"] = true;
Application.Current.Host.Settings.EnableFrameRateCounter = true;
}
InitializeComponent();
InitializePhoneApplication();
}
В этом случае тестируется пробный режим, а для тестирования полного режима можно закомментировать строчку «_settings["trialMode"] = true;».
Теперь, проверяя в каком режиме работает приложение, требуется читать ещё и значение из настроек. Вот полный код нового варианта такой проверки:
LicenseInformation _li = new LicenseInformation();
IsolatedStorageSettings _settings = IsolatedStorageSettings.ApplicationSettings;
// Constructor
public MainPage()
{
InitializeComponent();
if (_li.IsTrial() || (bool)_settings["trialMode"])
{
//Сделать что-то, доступное пробным пользователям
}
else
{
//Сделать что-то, доступное только платным пользователям
}
}
Может это и не лучший способ, но он работает.
Определить, работает ли приложение в тестовом или полном режиме очень просто. Вам остаётся только подумать над тем, какую функциональность сделать доступной в тестовом режиме, а это уже сложнее.
<< День #20. Уведомления (Push Notifications).| День #22. Trial (пробная) версия приложения. >>
Это двадцать первая статья серии «45 дней с Windows Phone 7».
Многие разработчики, создающие Windows Phone 7 Silverlight приложения, хотят использовать Silverlight, в том числе и для написания игр. Хотя основной платформой, позволяющей создавать игры для телефонов, является XNA, Silverlight также является мощной платформой для работы с графикой, поэтому игры, написанные на Silverlight, имеют такое же право на существование, как и XNA игры.

Если Вы создадите Silverlight Windows Phone 7 приложение (или XNA игру) и запустите его на эмуляторе, то данное приложение будет отображаться в списке всех установленных приложений телефона (данный список появляется при нажатии стрелочки вправо на главном экране). Но на реальном телефоне игры отображаются не в данном списке, а в специальном хабе «Games». Есть очень простой способ сделать так, чтобы Ваши приложения тоже отображались в данном хабе. Но делать это стоит, только если приложение действительно являются игрой. Попытка разместить приложение, не являющееся игрой, в хабе «Games» – повод для отказа в публикации приложения в Marketplace.
В первом дне данной серии мы рассматривали все файлы, входящие в проект Silverlight Windows Phone 7 приложения. В том числе и файл «WMAppManifest.xml» (он находится в папке «Properties»). Данный файл как раз и позволяет указать, что наше приложение является игрой и будет размещаться в хабе «Games».

Внутри файла «WMAppManifest.xml» находятся метаданные приложения, в том его имя, иконка, путь к стартовой странице и.т.д.
Кстати, изменение стартовой страницы – хороший способ ручного тестирования приложения. Например, вместо того, чтобы при отладке вначале загружать какую-то базовую страницу приложения, а уже потом с помощью навигации переходить на ту страницу, которую требуется отладить, можно сразу указать отлаживаемую страницу в качестве стартовой, а также передать ей некоторые параметры. Например, укажем, что вначале будет загружаться страница «ProductPage.xaml»:
<Tasks> <DefaultTask Name ="_default" NavigationPage="ProductPage.xaml?id=42"/> </Tasks>
Естественно, перед этим страницу «ProductPage.xaml» надо создать. Но вернёмся к задаче размещения нашего приложения в хабе «Games». Для этого изменим свойство «Genre» – жанр тега «App». Вот как выглядит данный тег по умолчанию (естественно, Ваших приложениях многие значения будут отличаться):
<App xmlns="" Genre="apps.normal"
ProductID="{6b6bf47b-9652-47d3-8758-fd1b11f99971}"
Title="Day22_AppsVsGames"
RuntimeType="Silverlight" Version="1.0.0.0"
Author="SergeyPugachev"
Description="An amazing demo on how to change your app's location."
Publisher="pugachve.info">
Значением жанра по умолчанию является «apps.normal». Поменяем данное значение на используемое для игр: «apps.games».
Теперь после запуска приложения на эмуляторе оно не будет отображаться в стандартном списке приложений, а так как хаба «Games» на эмуляторе нет, то приложение как будто исчезнет с телефона (запускаться из Visual Studio оно, конечно, продолжит). Далее приведу модифицированную версию тега «App»:
<App xmlns="" Genre="apps.games"
ProductID="{6b6bf47b-9652-47d3-8758-fd1b11f99971}"
Title="Day22_AppsVsGames"
RuntimeType="Silverlight" Version="1.0.0.0"
Author="SergeyPugachev"
Description="An amazing demo on how to change your app's location."
Publisher="pugachve.info">
Теперь при отладке приложения на реальном устройстве, Вы найдёте его в хабе «Games».

На данной фотографии моё приложение Вы найдёте в левом нижнем углу. Оно имеет стандартную иконку.