Очередная статья о создании Metro-приложений - Windows-приложений нового класса, выполняющихся под управлением платформы Metro, что входит в состав Windows 8, - будет посвящена работе с интернет-сервисами. Мы научимся разрабатывать приложения, работающие с каналами новостей RSS/Atom и поисковым сервисом Microsoft Bing.
Внимание! Перед чтением следует ознакомиться с обоими статьями из цикла "Начала Metro-программирования", опубликованными на сайте TheVista.ru ранее. Описанные в них приёмы программирования будут активно здесь использоваться.
1. Интернет-возможности платформы Metro
Итак, какие же возможности по работе с интернет-сервисами предоставляет нам платформа Metro? О, весьма богатые!
Высокоуровневые средства для работы с каналами новостей RSS и Atom - загрузки, разбора и вывода.
Высокоуровневые средства для загрузки и разбора данных, записанных в форматах XML и JSON (технологии AJAX и AJAJ).
Высокоуровневые средства для загрузки и вывода обычных веб-страниц.
Низкоуровневые средства для работы с сокетами TCP/IP, позволяющие обмениваться данными как по обычной компьютерной сети, так и с применением технологии Proximity (прямой обмен произвольными данными между устройствами с установлением между ними своего рода одноранговой сети).
Наконец, высокоуровневые средства для асинхронной загрузки файлов.
Эта статья будет посвящена первым трём пунктам из перечисленных ранее, а именно, работе с каналами новостей, загрузке данных JSON и выводу веб-страниц. В процессе изучения соответствующих инструментов мы напишем приложения просмотровщика каналов новостей и утилиты для поиска изображений по ключевому слову в сервисе Bing.
Также мы рассмотрим ещё два элемента интерфейса, ещё нам не знакомые. Первый из них позволит нам имитировать привычные по традиционным Windows-приложениям диалоговые окна. Это всплывающий элемент Metro, который может содержать любые элементы управления, что поддерживаются Metro; такие элементы обычно применяемые для ввода каких-либо данных. Второй элемент - фрейм HTML - позволит вывести в произвольном месте экрана любую веб-страницу, интернет-адрес которой мы укажем.
Начнём мы с рассмотрения инструментов для работы с каналами новостей как более простых в освоении и использовании.
2. Начинаем писать приложение просмотровщика каналов новостей
Запустим Visual Studio и создадим в нём новый проект Metro-приложения. Пусть он называется FeedReader.
А теперь - внимание! Откроем окно параметров приложения, переключимся на вкладку Capabilities и найдём в списке Capabilities пункт Internet (Client). Проверим, установлен ли присутствующий в этом пункте флажок (вообще-то, он должен быть установлен по умолчанию), и, если это не так, установим его. Тем самым мы дадим создаваемому приложению права на загрузку данных из Интернета. После чего закроем окно параметров и, если нужно, сохраним все заданные в нём установки.
На заметку Поскольку любое вновь создаваемое Metro-приложение уже имеет право на загрузку данных из Интернета, специально давать это право, равно как и проверять, имеется ли оно, не требуется.
Откроем файл default.html, где описывается интерфейс приложения, удалим всё содержимое парного тега <body> и введём в него следующий код:
div>[/code]
Здесь мы, прежде всего, создаём три блока, которые потом разместим на экране с применением сеточной разметки:
верхний — divHeader — включит в свой состав заголовок первого уровня hHeader, который мы используем для вывода заголовка самого канала новостей;
левый — divList — мы превратим в список Metro, выводящий перечень новостей;
правый — divContent — мы используем для вывода веб-страницы, содержащей полный текст выбранной в списке новости.
Помимо этого, мы создаём панель инструментов с кнопками Подписаться (выводит на экран всплывающий элемент, позволяющий подписаться на канал) и Обновить (обновляет содержимое канала, загружая его повторно). Эта панель инструментов будет находиться в верхней части экрана.
Наконец, мы создаём шаблон для списка, в котором будет выводиться содержимое канала новостей. Каждый пункт этого списка будет содержать список авторов новости, её содержимое и дату публикации.
Откроем файл default.css, где описывается оформление приложения, и создадим в нём стили, перечисленные далее.
[code]body {
display: -ms-grid;
-ms-grid-columns: 1fr 1fr;
-ms-grid-rows: auto 1fr;
}
#divHeader {
-ms-grid-column-span: 2;
-ms-grid-column-align: center;
}
#divList {
-ms-grid-row: 2;
height: 100%;
}
#divContent {
-ms-grid-row: 2;
-ms-grid-column: 2;
}[/code]
Эти три стиля создают давно знакомую нам сеточную разметку. Третий по счёту стиль также растянет список новостей на всю высоту блока divList (атрибут стиля height указывает высоту элемента интерфейса).
[code]#divList .win-item { padding: 10px; }[/code]
Этот стиль будет автоматически привязан к пунктам списка новостей и задаст для них внутренние отступы со всех сторон, равные 10 пикселам. (За внутренние отступы "отвечает" атрибут стиля padding.) Так мы визуально отодвинем пункты от краёв списка и друг от друга.
[code].item-authors {
font-style: italic;
text-align: right;
}[/code]
Этот стиль будет привязан к абзацу со списком авторов новости и задаст для него курсивное начертание шрифта (значение italic атрибута стиля font-style) и выравнивание по правому краю (значение right атрибута стиля text-align). Так мы визуально выделим список авторов новости.
[code].item-content {
padding-top: 10px;
padding-bottom: 10px;
}[/code]
Этот стиль будет привязан к блоку, в котором выводится содержимое новости. Он устанавливает внутренние отступы сверху (атрибут стиля padding-top) и снизу (атрибут стиля padding-bottom), равные 10 пикселам. Так мы немного отодвинем содержимое новости от списка её авторов и даты публикации.
[code].item-date {
text-align: right;
padding-right: 20px;
}[/code]
А этот стиль будет привязан к абзацу с датой публикации новости. Он задаст для неё выравнивание по правому краю и внутренний отступ справа в 20 пикселов (атрибут стиля padding-right) и также позволит выделить дату публикации.
Логику приложения мы оставим на потом. А пока что сохраним все исправленные файлы и оставим Visual Studio в покое.
3. Всплывающие элементы Metro
Сразу же после запуска данного приложения нам потребуется запросить у пользователя интернет-адрес канала новостей, на который он хочет подписаться. Сделать это можно двумя способами:
Мы можем поместить поле для ввода интернет-адреса и кнопку, собственно выполняющую подписку на канал, прямо в составе основного интерфейса приложения. Так сделать проще всего. Однако при этом данные поле ввода и кнопка, которые, скажем прямо, нужны далеко не всегда, будут присутствовать на экране постоянно, отнимая свободное пространство у других элементов интерфейса - списка новостей и содержимого выбранной новости.
Мы можем выводить поле ввода и кнопку только в тот момент времени, когда пользователь пожелает подписаться на канал новостей, нажав соответствующую кнопку. Так мы освободим пространство экрана (которого постоянно не хватает) для списка новостей и содержимого выбранной новости. С другой стороны, это потребует дополнительного кода, который будет выводить данные элементы управления, а потом скрывать их.
Платформа Metro ненавязчиво подталкивает нас к выбору второго способа, предоставляя исключительно удобные элементы управления, называемые всплывающими элементами.
Как уже говорилось ранее, всплывающие элементы (flyout) Metro по своему назначению аналогичны диалоговым окнам в традиционных Windows-приложениях. Они содержат какие-либо элементы интерфейса (кнопки, поля ввода, списки, фрагменты текста и др.), выводятся на экран, только когда в них возникает необходимость, и располагаются поверх основного интерфейса.
Всплывающие элементы могут выводиться на экран как программно, так и автоматически, после нажатия на кнопку в панели инструментов. Скрываться они также могут как программно, так и автоматически, после того как пользователь нажмёт на любой элемент интерфейса, не являющийся частью всплывающего элемента.
3.1. Создание всплывающего элемента
Всплывающий элемент, как и рассмотренные нами в предыдущих статьях список, панель инструментов и панель вывода, является элементами управления Metro. Он представляется объектом WinJS.UI.Flyout, имя которого следует указать в атрибуте data-win-control тега <div>, создающего элемент-основу.
[code]<div id="divFlyout" data-win-control="WinJS.UI.Flyout"></div>[/code]
Внутри этого тега пишется код, создающий элементы интерфейса, что будут присутствовать во всплывающем элементе.
[code]<div id="divFlyout" data-win-control="WinJS.UI.Flyout">
<div>
<label for="txtAddress">Интернет-адрес</label>
<br />
<input type="url" id="txtAddress" />
</div>
<div>
<input type="button" id="btnSubscribe" value="Подписаться" />
</div>
</div>[/code]
Создаём всплывающий элемент, содержащий поле ввода Интернет-адрес и кнопку Подписаться. (Тег <label> позволяет создать надпись для элемента интерфейса.)
HTML-код, создающий всплывающий элемент, может располагаться в любом месте кода интерфейса.
Во всплывающих элементах, предназначенных для ввода данных, не должны присутствовать кнопки простого закрытия или отмены ввода. (Такие кнопки в традиционных Windows-приложениях обычно имеют надпись Отмена или Закрыть.) Поскольку всплывающие элементы скрываются автоматически, после нажатия на любой элемент интерфейса, который не входит в их состав, подобные кнопки просто не нужны.
3.2. Работа со всплывающими элементами
Для вывода всплывающего элемента на экран применяется метод show объекта WinJS.UI.Flyout:
[code]<всплывающий элемент>.show(
<элемент интерфейса, возле которого он будет выведен>[,
<месторасположение>[,
<выравнивание>]]
)[/code]
Первым параметром данный метод принимает элемент интерфейса, возле которого всплывающий элемент будет выведен на экран. Этот параметр может представлять собой либо строку с именем нужного элемента интерфейса, заданным с помощью атрибута тега id, либо экземпляр объекта, представляющего этот элемент.
Вторым, необязательным, параметром указывается местоположение всплывающего элемента относительно элемента, заданного в первом параметре. Его значение должно представлять собой одну из следующих строк:
auto — месторасположением всплывающего элемента управляет сама платформа Metro (значение по умолчанию);
top — всплывающий элемент выводится выше указанного элемента;
bottom — ниже;
left — левее;
right — правее.
Третьим, также необязательным, параметром задаётся выравнивание всплывающего элемента. Этот параметр имеет смысл только в том случае, если всплывающий элемент выводится выше или ниже указанного в первом параметре. Значением третьего параметра должна быть одна из следующих строк: left (выравнивание по левому краю), center (выравнивание по центру; значение по умолчанию) и right (выравнивание по правому краю).
Метод show не возвращает значения.
[code]var ctrFlyout = document.getElementById("divFlyout").winControl;
ctrFlyout.show("btnAdd", "bottom", "right");[/code]
Выводим созданный ранее всплывающий элемент divFlyout ниже и правее кнопки btnAdd.
Помимо этого, объект WinJS.UI.Flyout поддерживает свойство hidden, метод hide и события beforeshow, aftershow, beforehide и afterhide, знакомые нам по объекту WinJS.UI.AppBar - панели инструментов (см. предыдущие статьи данного цикла).
[code]ctrFlyout.hide();[/code]
Скрываем всплывающий элемент сами, не дожидаясь, пока это сделает пользователь.
3.3. Вывод всплывающего элемента после нажатия кнопки на панели инструментов
Предположим, что нам требуется реализовать в приложении вывод всплывающего элемента на экран после нажатия кнопки в панели инструментов. Тогда нам крупно повезло — платформа Metro предлагает для этого стандартные средства, не требующие никакого программирования.
Создадим в панели инструментов кнопку и сделаем с ней две вещи. Во-первых, зададим для её свойства type строковое значение flyout. Во-вторых, укажем в другом её свойстве — flyout — всплывающий элемент, который требуется выводить на экран. Данный элемент может быть задан либо в виде строки с его именем (это единственный способ указать всплывающий элемент в HTML-коде, описывающем кнопку), либо в виде представляющего его экземпляра объекта.
Помимо этого, нам следует переместить HTML-код, создающий всплывающий элемент, таким образом, чтобы он находился перед кодом, формирующим саму панель инструментов с кнопкой, которая будет выводить его на экран. Если этого не сделать, всплывающий элемент не будет "найден".
[code]<button data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{id: 'btnAdd', label: 'Подписаться', icon: 'add', section: 'global', type: 'flyout', flyout: 'divFlyout'}"></button>[/code]
После нажатия этой кнопки на экране появится всплывающий элемент divFlyout.
3.4. Меню Metro Меню Metro схоже по внешнему виду и назначению с меню традиционных Windows-приложений. Его можно рассматривать как разновидность всплывающего элемента, поскольку оно ведёт себя сходным образом.
Само меню представляется объектом WinJS.UI.Menu. Имя этого объекта мы зададим в атрибуте data-win-control тега <div>, создающего элемент-основу.
[code]<div id="divMenu" data-win-control="WinJS.UI.Menu"></div>[/code]
Внутри этого тега помещается код, создающий пункты меню и разделители. Создаются они таким же образом, что и в случае панели инструментов, - с помощью тегов <button> и <hr> соответственно. Все они представляются объектом WinJS.UI.MenuCommand, который поддерживает знакомые нам свойства id, label, type, flyout, disabled и hidden.
[code]<div id="divMenu" data-win-control="WinJS.UI.Menu">
<button data-win-control="WinJS.UI.MenuCommand"
data-win-options="{id: 'btnSave', label: 'Сохранить'}"></button>
<button data-win-control="WinJS.UI.MenuCommand"
data-win-options="{id: 'btnSaveAll', label: 'Сохранить все'}"></button>
<hr data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{type: 'separator'}" />
<button data-win-control="WinJS.UI.MenuCommand"
data-win-options="{id: 'btnDelete', label: 'Удалить'}"></button>
</div>[/code]
Создаём меню с пунктами Сохранить, Сохранить всё и Удалить и разделителем между двумя последними пунктами.
HTML-код, создающий меню, может находиться в любом месте кода интерфейса.
Объект WinJS.UI.Menu поддерживает уже знакомые нам свойства disabled и hidden, методы getCommandById, show, hide, showCommands, hideCommands и showOnlyCommands и события beforeshow, aftershow, beforehide и afterhide.
[code]var ctrMenu = document.getElementById("divMenu").winControl;
ctrMenu.hideCommands(["btnSave", "btnDelete"]);
ctrMenu.show();[/code]
Скрываем пункты Сохранить и Удалить и выводим меню на экран.
Мы можем реализовать автоматический вывод меню на экран после нажатия кнопки в панели инструментов. Делается это так же, как и в случае обычных всплывающих элементов.
3.5. Создаём всплывающий элемент в приложении просмотровщика каналов новостей
Откроем в Visual Studio проект FeedReader, если уже его закрыли. Сейчас мы создадим в просмотровщике каналов новостей всплывающий элемент для указания интернет-адреса канала, на который хочет подписаться пользователь.
Переключимся на файл default.html. Отыщем тег <button>, создающий кнопку Подписаться (btnSubscribe), и исправим его так, чтобы он выглядел следующим образом:
[code]<button data-win-control="WinJS.UI.AppBarCommand"
data-win-options="{id: 'btnSubscribe', label: 'Подписаться', icon: 'add', section: 'global', type: 'flyout', flyout: 'divURL'}"></button>[/code]
Мы указали, чтобы после нажатия этой кнопки на экране появлялся всплывающий элемент divURL, который мы сейчас создадим...
...вставив перед кодом, формирующим панель инструментов, вот такой фрагмент:
[code]<div id="divURL" data-win-control="WinJS.UI.Flyout">
<div>
<label for="txtURL">Интернет-адрес</label>
<br />
<input type="url" id="txtURL" />
</div>
<div>
<input type="button" id="btnURL" value="Подписаться" />
</div>
</div>[/code]
Этот всплывающий элемент содержит поле ввода Интернет-адрес и кнопку Подписаться.
Отметим, что в данном элементе мы сформировали поле ввода интернет-адреса - особое поле ввода, предназначенное для указания именно интернет-адресов. Это один из новых элементов управления, поддержка которых появилась в языке HTML5. Чтобы создать такое поле ввода, достаточно задать для атрибута type формирующего это поле тега <input> значение url (как мы и сделали).
Обязательно сохраним исправленный файл, чтобы ничего не потерять.
4. Работа с каналами новостей RSS и Atom
Теперь займёмся собственно средствами платформы Metro, призванными обеспечить удобную работу с каналами новостей RSS и Atom.
4.1. Получение интернет-адреса канала
Что ж, интернет-адрес нужного канала новостей, представляющий собой строку, мы получили. И здесь мы столкнёмся с проблемой: механизмы Metro, работающие с каналами новостей, не "переваривают" интернет-адреса, заданные в виде строк.
Они манипулируют интернет-адресами, представляющими собой экземпляры объекта Windows.Foundation.Uri. Поэтому нам придётся создать экземпляр данного объекта, передав ему в качестве параметра строку с интернет-адресом.
[code]var sFeedURL = "rss.php";
var oFeedURL = new Windows.Foundation.Uri(sFeedURL);[/code]
Здесь мы взяли строку с интернет-адресом канала RSS портала TheVista.ru и создали на его основе экземпляр объекта Windows.Foundation.Uri, хранящего этот интернет-адрес.
Кстати, объект Windows.Foundation.Uri поддерживает свойство absoluteUri. Оно возвращает интернет-адрес, на основе которого был создан его экземпляр, в виде строки. Это свойство нам очень пригодится впоследствии.
4.2. Создание клиента новостей и загрузка содержимого канала
Получив интернет-адрес в поддерживаемом платформой Metro формате, мы можем приступить к собственно загрузке содержимого данного канала новостей. Выполняется это в два этапа.
На первом этапе мы создадим так называемого клиента новостей, который и выполнит загрузку канала. Он представляется экземпляром объекта Windows.Web.Syndication.SyndicationClient, который нам потребуется создать.
[code]var oFeedClient = new Windows.Web.Syndication.SyndicationClient();[/code]
На втором этапе мы вызовем у готового клиента новостей метод retrieveFeedAsync, собственно запускающий процесс загрузки содержимого канала. Единственным параметром этому методу передается интернет-адрес канала в виде экземпляра объекта Windows.Foundation.Uri.
Метод retrieveFeedAsync возвращает в качестве результата обязательство, для которого мы укажем в вызове метода then функцию. Она выполнится после успешной загрузки содержимого указанного нами канала новостей и получит в качестве результата экземпляр объекта Windows.Web.Syndication.SyndicationFeed, представляющий этот канал.
Вся остальная работа с загруженным каналом новостей будет протекать в теле этой функции.
[code]oFeedClient.retrieveFeedAsync(oFeedURL).then(function(feed) {
//Выполняем чтение загруженного канала
});[/code]
Надо сказать, что мы можем указать в вызове метода then еще две функции - вторым и третьим его параметрами соответственно. Первая из них выполнится при возникновении ошибки, а вторая будет периодически вызываться в процессе загрузки канала. Однако эти функции можно и не указывать, как во многих случаях и поступают.
4.3. Получение сведений о канале новостей
Объект Windows.Web.Syndication.SyndicationFeed, представляющий канал новостей, поддерживает несколько полезных для нас свойств, которые позволят нам узнать основные сведения о канале. Эти свойства перечислены далее.
title — заголовок канала
subtitle — подзаголовок канала
rights — сведения об авторских правах
Значением всех этих свойств является экземпляр особого объекта, который и хранит соответствующие свойству данные. Чтобы получить их в строковом виде, мы обратимся к свойству text этого объекта.
Значением этих свойств является экземпляр уже знакомого нам объекта Windows.Foundation.Uri. Если канал не содержит значка или логотипа, соответствующее свойство будет хранить значение null.
[code]<img id="imgLogo" />
. . .
var imgLogo = document.getElementById("imgLogo");
var oLogoURL = feed.imageUri;
if (oLogoURL) {
var sLogoURL = oLogoURL.absoluteUri;
imgLogo.src = URL.createObjectURL(sLogoURL);
}[/code]
Проверяем, имеет ли канал новостей логотип, и, если имеет, выводим его в элементе графического изображения imgLogo.
lastUpdatedTime — дата и время последнего изменения содержимого данного канала в виде экземпляра объекта Date.
id — внутренний идентификатор канала в виде строки.
4.4. Получение отдельных новостей
Загрузив канал, мы можем получить все новости, составляющие его содержимое. Для этого мы воспользуемся свойством items объекта Windows.Web.Syndication.SyndicationFeed, представляющего канал. Это свойство хранит экземпляр того же объекта-коллекции, что возвращается методами, выполняющими получение списка файлов (см. предыдущие статьи данного цикла).
[code]var oItems = feed.items;
var arrItems = [];
for (var i = 0; i < oItems.size; i++) {
arrItems.push(oItems);
}[/code]
Получаем список новостей, имеющихся в загруженном ранее канале, и помещаем их в массив arrItems.
Каждая новость — элемент полученной ранее коллекции — представляется экземпляром объекта Windows.Web.Syndication.SyndicationItem. Перечисленные далее свойства этого объекта хранят сведения о новости.
title — заголовок новости
summary — содержимое новости формата RSS
rights — сведения об авторских правах создателей новости
Значением всех этих свойств является тот же экземпляр объекта, что возвращается одноимёнными свойствами канала (см. ранее).
content — содержимое новости формата Atom
Значением этого свойства является экземпляр объекта Windows.Web.Syndication.SyndicationContent. Чтобы получить содержимое новости Atom в строковом виде, следует обратиться к свойству text данного объекта.
authors — список авторов новости
Значением этого свойства будет тот же экземпляр объекта-коллекции, что возвращается методами, выполняющими получение списка файлов. Каждый из элементов этой коллекции представляет собой экземпляр объекта Windows.Web.Syndication.SyndicationPerson, представляющий автора новости. Свойство name данного объекта возвращает имя автора, а свойство email — его адрес электронной почты; оба значения представляют собой строки.
links — список всех интернет-адресов, имеющихся в составе новости.
Значением этого свойства будет аналогичный экземпляр объекта-коллекции. Каждый из его элементов представляет собой экземпляр объекта Windows.Web.Syndication.SyndicationLink, представляющий интернет-адрес из состава новости. Свойство uri данного объекта возвращает сам интернет-адрес в виде экземпляра объекта Windows.Foundation.Uri.
publishedDate — дата и время публикации новости в виде экземпляра объекта Date.
Теперь дадим необходимые пояснения.
Содержимое новости можно получить либо из свойства content, либо из свойства summary. Обычно сначала проверяют, хранится ли что-либо в свойстве content (не равно ли её значение null); если же там ничего нет, используют значение свойства summary.
В списке интернет-адресов, имеющихся в составе новости, самым первым идёт интернет-адрес, ведущий на веб-страницу с полным текстом новости. Поэтому, как правило, в приложениях для чтения каналов новостей используют только первый интернет-адрес из списка.
[code]var arrItems = [], oI, sAuthors, sContent;
for (var i = 0; i < feed.items.size; i++) {
oI = feed.items;
sAuthors = "";
for (var j = 0; j < oI.authors.size; j++) {
if (sAuthors != "") {
sAuthors += ", ";
}
sAuthors += oI.authors[j].name;
}
if (oI.content) {
sContent = oI.content.text;
} else {
sContent = oI.summary.text;
}
arrItems.push({
title: oI.title.text,
authors: sAuthors,
content: sContent,
url: oI.links[0].uri.absoluteUri,
date: oI.publishedDate
});
}[/code]
Перебираем все новости из загруженного канала и для каждой добавляем в массив arrItems описывающий её элемент - экземпляр объекта Object. Он включит заголовок новости; строку со списком её авторов, чьи имена разделены запятыми; содержимое; первый интернет-адрес и дату публикации.
Полученный массив, кстати, можно использовать в качестве массива данных для формирования списка Metro. Чем мы вскоре и займёмся.
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.035 секунд (Общее время SQL: 0.015 секунд - SQL запросов: 53 - Среднее время SQL: 0.00028 секунд))