Введение в разработку приложений для Windows 8 с использованием HTML, CSS и JavaScript

Быстрый старт

Разбить на страницы
Показывать лекцию целиком

Файлы к данной лекции Вы можете скачать здесь.

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

Настоящий быстрый старт: шаблон Пустое приложение

Конечно, мы должны начать с того, чтобы отдать дань уважения классическому приложению "Hello World". Мы можем сделать это, не написав ни единой строчки кода. Нам лишь нужно создать новое приложение из шаблона в Visual Studio.

  • Запустите Visual Studio Express. Если вы делаете это впервые, вам предложат получить лицензию разработчика. Сделайте это, так как иначе вы не сможете продолжать!
  • Щёлкните Создать проект… (New Project…) в окне Visual Studio или используйте команду меню Файл > Создать проект (File > Create Project)
  • В появившемся диалоговом окне (Рис. 2.1) убедитесь, что выбрали в разделе Шаблоны (Templates), слева, JavaScript и выберите шаблон Пустое приложение (Blank Application) в центральной части окна. Задайте имя (HelloWorld подойдёт), папку и нажмите OK. (рис 2.1) Диалоговое окно Создать проект, использующее светлую тему пользовательского интерфейса. (Смотрите команду меню Сервис > Параметры (Tools > Options) и измените тему в разделе Среда>Общие (Environment>General)). Я использую здесь светлую тему, так как она лучше смотрится на белом фоне страниц
  • После того, как Visual Studio создаст проект, нажмите кнопку Начать отладку (Start Debugging) (или нажмите F5 или выберите команду меню Отладка > Начать отладку (Debug > Start Debugging)). Подразумевая то, что всё у вас установлено верно, вы должны увидеть что-то вроде Рис. 2.2 на своём экране. (рис 2.2) Единственная интересная часть окна приложения HelloWorld. Сообщение - это, как минимум, лучшее приглашение к написанию большего количества кода, чем нужно для вывода стандартного приветствия первого приложения!
  • По умолчанию, Visual Studio запускает отладчик в режиме локального компьютера (local machine), в котором приложение запускается в полноэкранном режиме в вашей операционной системе. В результате мы сталкиваемся с неудобством, когда отладчик скрывается, если только вы не используете систему с несколькими мониторами, когда вы можете открыть Visual Studio на одном мониторе и своё приложение для Магазина Windows - на другом. Посмотрите материал "Выполнение приложений для Магазина Windows на локальном компьютере" (http://msdn.microsoft.com/library/windows/apps/hh441483.aspx) для того, чтобы больше об этом узнать.

    Visual Studio предлагает два других режима отладки, которые можно выбрать из выпадающего списка на панели инструментов (Рис. 2.3), или в меню Отладка > Свойства [Имя приложения] ( Debug > [Appname] Properties), Рис. 2.4.

    (рис 2.3) Параметры отладки в панели инструментов Visual Studio (рис 2.4) Параметры отладки в окне свойств приложения в Visual Studio

    Параметр Удалённый компьютер (Remote Mashine) позволяет вам запускать приложение на другом устройстве, что абсолютно типично при работе с устройствами, которые не способны выполнять настольные приложения, как, например, ARM-устройства (и если вы видите лишь эту опцию в примере проекта, активная платформа решения, возможно, установлена в ARM). Настройка здесь достаточно проста: смотрите материал "Выполнение приложений для Магазина Windows на удаленном компьютере" (http://msdn.microsoft.com/library/windows/apps/hh441469.aspx), и я рекомендую, чтобы вы хорошо с ним ознакомились. Кроме того, если проект не загружен в Visual Studio, меню Отладка предлагает команду Присоединиться к процессу (Attach to process), которая позволяет отлаживать уже запущенные приложения. Смотрите материал "Запуск сеанса отладки (JavaScript)" (http://msdn.microsoft.com/library/windows/apps/hh771032.aspx).

    Имитатор (simulator) так же весьма интересен, а на мой взгляд - самый интересный инструмент, и место, где, по-моему, вы будете проводить очень много времени. Он дублирует ваше окружение внутри новой сессии входа в систему и позволяет вам управлять ориентацией устройства, устанавливать различные разрешения и коэффициенты масштабирования, имитировать события касаний экрана и работать с данными, которые поступили от API определения местоположения. На Рис. 2.5 вы можете видеть приложение Hello World в имитаторе, с отмеченными дополнительными элементами управления. Подробнее об имитаторе вы узнаете далее, хотя вы так же можете захотеть прочесть материал "Выполнение приложений для Магазина Windows на имитаторе" (http://msdn.microsoft.com/library/windows/apps/hh441475.aspx).

    (рис 2.5) Приложение HelloWorld работает в имитаторе, справа добавлены подписи к кнопкам. На самом деле, шаблон "Пустое приложение" оправдывает своё название!

    Поверх остальных окон (Always on top)

    Режим мыши(Mouse pointer)

    Базовый сенсорный режим (Touch emulator)

    Сенсорный режим с жестом сжатия/масштабирования (Emulate touch zooming)

    Сенсорный режим с вращением (Emulate touch rotation)

    Повернуть по часовой стрелке на 90 градусов (Rotate device 90 clockwise)

    Повернуть против часовой стрелки на 90 градусов (Rotate device 90 counter-clockwise)

    Изменить разрешение (Set resolution/scaling)

    Задать положение (Set GPS Coordinates)

    Копирование снимка экрана (Take a screenshot)

    Параметры снимка экрана (Screenshot settings)

    Справка (Help)

    Врезка: Как Visual Studio запускает приложение?

    Visual Studio разворачивает приложение так же, как это происходит при получении приложения из Магазина Windows. Приложение появляется на Начальном экране, где вы можете деинсталлировать его. Деинсталляция очищает папки с данными приложения, сведения о его состояниях, что весьма полезно при отладке.

    Здесь нет ничего необычного: развёртывание можно произвести и с использованием инструментов командной строки. Для того, чтобы увидеть подробности, воспользуйтесь командой Магазин > Создать пакеты приложения (Store > Create App Package) в Visual Studio, выберите Нет в параметре, отвечающем за отправку в Магазин Windows, и вы увидите диалоговое окно, позволяющее вам сохранить пакет приложения там, где вы захотите. В указанной папке вы найдете пакет appx, сертификат безопасности и пакетный файл, который называется Add-AppxDevPackage. Этот файл содержит скрипты PowerShell, которые разворачивают приложение и ресурсы, от которых оно зависит.

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

    Структура проекта Пустое приложение

    Приложение, созданное по шаблону Пустое приложение (Blank App), не имеет большого количества визуальных элементов, оно предоставляет определенную структуру проекта. Вот, что вы можете найти после создания проекта по шаблону, в Обозревателе проектов Visual Studio (Рис. 2.6).

  • default.html Cтартовая страница приложения.
  • <Appname>_TemporaryKey.pfx Файл временной электронной подписи, создаваемый при первом запуске.
  • package.appmanifest Файл-манифест. При открытии этого фйала отображается редактор манифеста Visual Studio (ниже в этой лекции мы рассмотрим его). Я рекомендую вам уделить несколько минут на то, чтобы изучить его. Например, там вы увидите ссылки на изображения, упомянутые ниже, флаг у возможности Интернет (клиент), страницу default.html, указанную как стартовая страница, и различные другие настройки приложения. Мы рассмотрим это в данном учебном курсе; подробности вы можете найти в материалах "Пакеты приложений и их развертывание" (http://msdn.microsoft.com/library/windows/apps/hh464929.aspx) и "Конструктор манифеста" (http://msdn.microsoft.com/library/windows/apps/br230259.aspx). И, если вы хотите просмотреть XML-файл манифеста напрямую, щёлкните по нему правой кнопкой и выберите команду Перейти к коду (View Code).
  • Папка css содержит файл default.css, где вы увидите структуры медиа-запросов для четырёх состояний просмотра, которые следует учитывать всем приложениям. Мы увидим это в действии в следующем разделе и обсудим подробности в лекции 6, "Макет".

    Папка images содержит четыре образца изображения, и если только вы не хотите выглядеть недалёким разработчиком, вы всегда будете менять эти изображения на собственные перед отправкой приложений в Магазин Windows (и, кроме того, создавать масштабированные версии, как мы увидим в лекции 3, "Анатомия приложения и навигация по страницам".

  • logo.png Изображение по умолчанию для стартовой страницы (размер 150х150 пикселей, 100% масштаб)
  • smallogo.png Изображение размером 30х30 для уменьшенной стартовой страницы и для других мест, используемое во время выполнения программы.
  • splashscreen.png Изображение размером 620х300, которое будет показано во время загрузки приложения.
  • storelogo.png Изображение размером 50х50, которое будет показано в Магазине Windows. Оно должно быть частью пакета приложения, однако, не используется во время выполнения программы в Windows.
  • Папка js содержит файл default.js.

    Папка Ссылки (References) указывает на CSS и JS-файлы библиотеки WinJS. Мы можете открыть любой из них для того, чтобы посмотреть, как устроена WinJS. (Обратите внимание на то, что если вы нуждаетесь в поиске по этим файлам, вы должны открыть конкретный файл и выполнять поиск в нём. Поиск по всему проекту или решению в данном случае не поддерживается).

    (рис 2.6) Проект, построенный по шаблону Пустое приложение, полностью раскрыт в Обозревателе решений

    Как можно ожидать, в проекте этого типа не так уж много кода, специфичного для приложения. Например, тело HTML-документа имеет лишь один абзац, который вы можете заменить на "Hello World", если вы чувствуете, что не можете без этого обойтись. Что гораздо важней - так это ссылки на компоненты WinJS: основной файл со стилями (ui-dark.css или ui-light.css), файлы base.js и ui.js:

    <!DOCTYPE html>	
    <html>	
    <head>	
    <meta charset="utf-8">	
    <title>Hello World</title>
    
    <!-- Ссылки WinJS -->	
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>	
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>	
    
    <!-- Ссылки HelloWorld -->	
    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>	
    </head>	
    <body>	
    <p>Content goes here</p>	
    </body>	
    </html>

    Как правило, такие ссылки присутствуют всегда (возможно, с ui-light.css) в каждом из HTML-файлов вашего проекта. Двойные // в путях WinJS указывают на библиотеки с разделяемым доступом, а не на файлы в пакете вашего приложения, в то время, как одиночные / указывают на корневой каталог вашего раздела. Помимо этого, всё остальное - это стандартный HTML5, поэтому вы можете свободно добавлять дополнительные HTML-теги и наблюдать за производимым ими эффектом.

    Что касается JavaScript, то default.js просто содержит базовый код активации WinJS, находящийся в событии WinJS.Application.onactivated вместе с заглушкой для события, которое называется WinJS.Application.oncheckpoint:

    (function () { "use strict";
    
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    
    app.onactivated = function (args) {
    if (args.detail.kind === activation.ActivationKind.launch) {
    if (args.detail.previousExecutionState !==
    activation.ApplicationExecutionState.terminated) {
    // TODO: Это приложение было вновь запущено. Инициализируйте
    // приложение здесь.
    } else {
    // TODO: Это приложение вновь активировано после приостановки.
    // Восстановите состояние приложения здесь.
    }
    args.setPromise(WinJS.UI.processAll());
    }
    };
    
    app.oncheckpoint = function (args) {
    };
    
    app.start();
    })();

    Мы вернемся к checkpoint в лекции 3. Сейчас, вспомните из лекции 1, что приложение может быть активировано различными способами. Это отражено в свойстве args.detail.kind, значения которого принадлежат перечислению Windows.ApplicationModel.Activation.ActivationKind.

    Когда приложение запущено прямо со своей плитки на Начальное экране (или запущено в отладчике, как у нас), вид активации имеет значение launch. Как мы увидим далее, другие значения говорят нам о том, что приложение активировано по запросу сервиса, наподобие контракта поиска или общего доступа к данным, путём ассоциации с типом файла, с помощью средства выбора файлов, посредством протокола и в других случаях. В случае с видом активации launch, другая порция данных из перечисления the Windows.ApplicationMode.- Activation.ApplicationExecutionState говорит нам о состоянии исполнения приложения до этого события. Больше об этом будет в лекции 3, а комментарии в стандартном коде выше должны пока удовлетворить ваше любопытство.

    А что такое Есть похожая функция WinJS.Binding.processAll, которая обрабатывает атрибуты data-win-bind (лекция 4) и WinJS.Resources.processAll, которая выполняет разрешение ресурсов атрибута data-win-res . Что касается args.setPromise, этот механизм касается отложенного выполнения, и мы отложим его рассмотрение до лекции 3.

    Короткий вызов app.start(); расположенный в нижней части кода, так же очень важен. Он позволяет нам быть уверенными в том, что различные события, которые поставлены в очередь при запуске приложения, будут обработаны. Мы рассмотрим это подробнее в лекции 3.

    Наконец, вы можете спросить: "Зачем нужна эта сложная конструкция Обратитесь ко второй главе книги "High performance JavaScript" (O'Reilly, 2010), Nicholas Zakas, для того, чтобы узнать, как область видимости влияет на производительность..

    Вы можете объявлять переменные в глобальном пространстве имен, конечно, и содержать их в порядке, WinJS предоставляет средства для задания ваших собственных пространств имен и классов (смотрите WinJS.Namespace.define и WinJS.Class.define), опять же, помогая минимизировать вмешательство в глобальное пространство имен.

    Познакомьтесь с Visual Studio. Если вы новичок в Visual Studio, то поначалу вы можете неуверенно чувствовать себя в этой инструментальной среде, так как она имеет множество функций, даже в Экспресс-версии. Для того, чтобы вы могли быстро ознакомиться с этой средой, я подготовил 10-минутный ролик, Video 2-1, который расположен в дополнительных данных к этой лекции для того, чтобы показать вам базовый рабочий процесс и другие основные вещи.

    Врезка: Написание кода в режиме отладки

    Из-за динамической природы JavaScript впечатляет то, что команда разработки Visual Studio нашла способ заставить IntelliSence весьма прилично работать в редакторе кода Visual Studio. (Если вы незнакомы с IntelliSence, это сервис для повышения производительности труда, который обеспечивает автозавершение кода и всплывающие подсказки по API в процессе работы. Больше вы можете узнать в материале "IntelliSence для JavaScript" (http://msdn.microsoft.com/library/bb385682.aspx)). При этом можно использовать полезный трюк, который позволяет IntelliSence работать даже лучше - это писать код, когда Visual Studio находится в режиме отладки. То есть, установить точку останова в подходящем месте вашего кода и запустить приложение в отладчике. Когда вы достигнете этой точки останова, вы можете начать писать и править код, и, так как контекст скрипта полностью загружен, IntelliSence будет работать с уже созданными экземплярами переменных, а не только с тем, что этот механизм может получить из исходного кода. Кроме того, вы можете использовать окно интерпретации (Immediate) для того, чтобы непосредственно в нём исполнять код и видеть результаты. (Однако, вам понадобится перезапустить приложение для того, чтобы получить возможность исполнять новый код).

    Быстрый старт №1: "Here My Am!" и введение в Blend для Visual Studio

    Когда моему сыну было три, он никогда - несмотря на то, что был рождён от двух инженеров-родителей и имел двух инженеров среди бабушек и дедушек - не заглядывал в углы и не появлялся в комнате со словами "Hello world!" (Привет, мир!). Нет, его особенной фразой была "Here my am!" (Вот и я!). Используя этот вариант представления себя вселенной, наше следующее приложение будет захватывать изображение с камеры, определять ваше местоположение на карте и передавать эти данные с помощью чудо-кнопки Общий доступ в Windows 8. Звучит сложно? К счастью, API WinRT делают это весьма простой задачей.

    Врезка: Сколько времени понадобится, чтобы написать это приложение?

    Написание этого приложения заняло у меня примерно три часа. "Конечно", - подумаете вы, - "вы уже написали кучу приложений, поэтому это для вас так просто!". Хорошо, и да, и нет. Во-первых, я, кроме того, писал данную часть главы в то же самое время и старался произвести код, подходящий для повторного использования. Но гораздо важнее то, что написание программы заняло у меня мало времени, так как я знал, как использовать мои инструменты, в особенности - Blend, и я знал, где я могу найти код, который уже делает большую часть из того, чего я хочу. Я имею в виду примеры из Windows SDK, которые вы можете загрузить с ресурса http://code.msdn.microsoft.com/windowsapps/.

    Как можно будет судить по множеству отличных примеров в этом учебном курсе, я надеюсь, что вы загрузите полный их набор. Перейдите по ссылке выше, найдите ссылку "Windows 8 app samples". Эта ссылка приведет вас на страницу, где вы можете получить .zip-файл, который содержит все примеры на JavaScript. Распаковав его однажды, заведите себе привычку просматривать эту папку на предмет любых API или функций, которые вам интересны. Например, код, который я использую ниже для реализации захвата данных с камеры и реализации обмена данными, взят из пары примеров. (Да, если вы откроете пример, который кажется поддерживающим только отладку на удаленном компьютере, целевая платформа, возможно, установлена в значение ARM - измените её на Any CPU для локальной отладки).

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

    Проектирование каркаса приложения

    Прежде чем мы начнём работу над кодом, сначала посмотрим на дизайнерский каркас этого приложения. О, дизайн? Да. Возможно, впервые в истории Windows, создана настоящая философия дизайна для приложений. В прошлом, с традиционными настольными приложениями, это было похоже на картину, где "что-то происходит". Конечно, были какие-то руководства по пользовательским интерфейсам, но разработчики обычно делали всё, что считали нужным, реализовывали любой опыт взаимодействия пользователя и приложения, который казался им правильным. Например, это могло выглядеть как наборы флагов в четыре уровня глубиной, спрятанные в серии модальных диалоговых окон. Естественно, подобные вещи имели смысл для определенных разработчиков; имели ли они значение для кого-нибудь еще - весьма спорный вопрос.

    Если вы когда-либо претендовали или собирались претендовать на то, чтобы быть дизайнером, сейчас - самое время передать эстафету тому, кто по-настоящему в этом разбирается, или отложить занятия программированием на год или два, и потратить это время на саморазвитие. Проще говоря, дизайн имеет значение в приложениях для Магазина Windows, и он определяет разницу между преуспевающими приложениями и приложениями, которые просто существуют в Магазине и не пользуются популярностью. И, когда у вас есть дизайн, его легче реализовать, так как вам не придётся принимать дополнительных решений о дизайне при написании кода. (Если вы всё еще хотите влезть в шкуру дизайнера и работать с приложениями вроде Adobe Illustrator, не забудьте посетить ресурс "Разработка интерфейсов пользователя для приложений" (http://msdn.microsoft.com/library/windows/apps/hh779072) для того, чтобы воспринять философию и подробности о дизайне приложений Магазина Windows, а так же - специальные ресурсы для дизайнеров).

    Когда у меня появилась идея этого приложения, я нарисовал простой каркас приложения, позволил нескольким дизайнерам посмеяться надо мной за моей спиной (и предложить улучшения) и остановился на макетах для полноэкранного режима, портретного, прикрепленного и заполняющего режимов просмотра, как показано на Рис. 2.7 и Рис. 2.8.

    Замечание. Традиционные табличные каркасы хороши для того, чтобы показать статичный вид приложения, но в "быстром и динамичном" окружении Windows 8 очень важен динамический аспект приложения - анимации и движение. Отличный дизайн приложения включает в себя не только соглашения о том, где будет расположено содержимое, но и о том, как оно будет реагировать на действия пользователя. Лекция 5 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript" обсуждает различные виды встроенных анимаций, которые можно использовать для этих целей. (рис 2.7) Полноэкранный альбомный макет и макет для заполняющего режима просмотра. Эти режимы просмотра обычно используют одинаковые макеты (с теми же полями), в которых некоторые части пропорционально уменьшены по ширине (рис 2.8) Макет для прикрепленного просмотра (слева, только для альбомного режима) и полноэкранный портретный макет (справа). Они не масштабируются

    Врезка: Проектирование для всех четырех режимов просмотра

    Так же, как я размышлял о четырех режимах просмотра для "Here my am!", я рекомендую вам сделать то же самое по одной простой причине: ваше приложение окажется в каждом из этих режимов просмотра независимо от того, приспособили вы его для этого или нет. Режимами просмотра управляют не приложения, а пользователи, поэтому, если вы не разработаете дизайн для каждого из возможных состояний, ваше приложение, вполне возможно, будет выглядеть отвратительно в этих состояниях. Вы можете, как показано в лекции 6, заблокировать ориентацию экрана в портретном или альбомном режиме, если захотите, но это оправданно в целях расширения опыта взаимодействия пользователя и приложения и никак не может служить оправданием лени разработчика. В итоге, если только у вас нет особенных причин не делать этого, каждая страница вашего приложения должна быть приспособлена к каждому из четырех режимов просмотра.

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

    Один из важных аспектов дизайна приложений для Магазина Windows заключается в понимании единообразного стиля макета: размера шрифтов заголовков, их расположения, определенные размеры границ, особенности сеточной раскладки и так далее (как отмечено на вышеприведенных рисунках). Эти рекомендации способствуют высокому уровню единообразия стиля приложений, в итоге, пользователь может интуитивно, основываясь на мышечной памяти, использовать основные элементы пользовательского интерфейса. Некоторые из этих рекомендаций можно найти в документе "Создание макета приложения" (http://msdn.microsoft.com/library/windows/apps/hh872191.aspx), их можно увидеть реализованными в шаблонах приложений вместе с другими аспектами дизайна. Это - одна из причин, по которой Microsoft обычно рекомендует начинать создание нового приложения с шаблона, начиная с него разработку. То, что я показал в вышеприведенных каркасах, отражает макет, предоставленный одним из более сложных шаблонов. В то же время, узнаваемый стиль приложений - это стартовая точка, но не жёсткое требование - приложения могут отступать от них, когда у этого есть смысл. При отсутствии же весомых причин для отступления, подтвержденных чётким дизайн-проектом, лучше от данных рекомендаций не отходить.

    Хватит говорить! Давайте просто примем к сведению, что у нас есть отличный дизайн для дальнейшей работы, наши дизайнеры потягивают капучино, удовлетворённые результатами своей работы. Теперь наша задача заключается в том, чтобы наполнить этот дизайн жизнью.

    Создаем разметку

    Для целей создания разметки, макета, настройки внешнего вида приложения, вы можете добавить в свой арсенал мощный инструмент - Blend для Visual Studio. Как вы можете знать, Blend был доступен (по более высокой цене) для дизайнеров и разработчиков, работающих с XAML (фреймворк для визуализации, которым пользуются приложения, написанные на C#, Visual Basic и C++). Теперь Blend бесплатен и поддерживает HTML, CSS и JavaScript. Я выделил последнее, так как он не только может загружать разметку и стили: он загружает и исполняет ваш код, прямо на монтажной панели (Artboard, рабочая поверхность, на которой располагаются элементы), так как этот код часто влияет на DOM, стиль элементов и так далее. И здесь присутствует Интерактивный режим (Interactive mode)… но я забегаю вперед!

    Blend и Visual Studio похожи на две стороны одной медали: они совместно используют проекты с одинаковыми форматами файлов и имеют команды для лёгкого переключения между ними, в зависимости от того, на чём вы хотите сосредоточиться - на дизайне или на разработке. Для того чтобы показать это, начнём создание приложения "Here My Am!" в Blend. Так же, как мы поступали ранее в Visual Studio, запустите Blend, выполните команду Создать проект… (New Project), выберите тип проекта - Пустое приложение (Blank App). В итоге, будет создан проект с точно такой же структурой, как ранее (Замечание: В файле Video 2-2 показаны эти шаги).

    Последуем практике написания разметки страницы в HTML - без стилей, без кода, и не обращая внимание на несколько классов, которые понадобятся нам для настроек стилей - поместим нижеприведенный код в элемент body страницы default.html, (заменяя строку <p>Content goes here</p>):

    <div id="mainContent">
    <header aria-label="Header content" role="banner">
    <h1 class="titlearea win-type-ellipsis">
    <span class="pagetitle">Here My Am!</span>
    </h1>
    </header>
    <section aria-label="Main content" role="main">
    <div id="photoSection" aria-label="Photo section">
    <h2 class="group-title" role="heading">Photo</h2>
    <img id="photo" src="images/taphere.png"
    alt="Tap to capture image from camera" role="img" />
    </div>
    <div id="locationSection" aria-label="Location section">
    <h2 class="group-title" role="heading">Location</h2>
    <iframe id="map" src="ms-appx-web:///html/map.html" aria-label="Map"></iframe>
    </div>
    </section>
    </div>

    Здесь мы видим пять элементов: главный заголовок, два подзаголовка, место для фотографии (по умолчанию - с изображением, содержащим инструкцию "коснитесь здесь" (tap here)) и элемент Если вы самостоятельно выполняете данный проект в Blend, изображение taphere.png следует добавить в проект, в папку images. Щёлкните правой кнопкой мыши по этой папке, выберите команду Добавить > Существующий элемент (Add > Existing Item) и затем, перейдя к папке images готового примера, выберите taphere.png. Файл изображения будет скопирован в ваш текущий проект.

    Вы можете видеть, что некоторым элементам назначены классы стилей. Они начинаются с Существуют две стандартных таблицы стилей - ui-dark.css (тёмная тема) и ui-light.css (светлая тема). Тёмные стили рекомендованы для приложений, которые работают с мультимедийными данными, когда тёмный фон позволяет выделить графические элементы. Мы будем использовать именно этот лист стилей, так как мы создаём программу для захвата фотографий. Светлая таблица стилей рекомендована для приложений, которые работают, в основном, с текстовым содержимым WinJS. Вы можете просмотреть их в Blend, используя закладку Правила стилей (Style Rules), показанную на Рис. 2.9. Другие стили, такие, как titlearea, pagetitle и group-title подразумевают, что вы определили их в вашем собственном листе стилей, тем самым переопределив стили WinJS для конкретных элементов.

    (рис 2.9) В Blend, закладка Правила стилей (Style Rules) позволяет вам просмотреть таблицу стилей WinJS и увидеть, что именно содержит каждый стиль. Обратите внимание на строку поиска под закладкой. Если вам нужно отыскать какой-то определенный стиль, можно не тратить время, просматривая их список. Достаточно начать вводить его имя в строке поиска и позволить компьютеру делать его работу!

    Страница, которую мы загрузим в элемент iframe, map.html, это часть нашего пакета приложения, которую мы скоро добавим, но обратите внимание на то, как мы ссылаемся на неё. Протокол ms-appx-web:/// показывает, что iframe и его содержимое будут исполняться в веб-контексте (представленном в лекции 1), тем самым, позволяя нам загружать удаленный скрипт для элемента управления карт Bing. Тройной слэш, одна из его частей, а точнее - третий слэш - это краткая запись для "пакета текущего приложения" (значение, которое вы можете получить из document.location.host), таким образом, нам не нужно создавать абсолютные URI для содержимого, которое находится в пакете.

    Для того, чтобы показать, что страницу следует загрузить в локальном контексте, протокол выглядит как ms-appx://. Важно помнить о том, что скрипты не могут разделяться между этими контекстами (включая переменные и функции), относительные пути оказываются в том же самом контексте, и взаимодействие между ними осуществляется посредством функции HTML5 postMessage, как мы увидим ниже. Это предотвращает возможность управления вашим приложением различными веб-сайтами и доступ к API WinRT.

    Кроме того, я включил в состав элементов различные атрибуты aria-* (так же, как это сделано в шаблоне), которые нужны для поддержки приложением специальных возможностей. Мы рассмотрим специальные возможности в подробностях в лекции 6 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", но важно, чтобы с самого начала помнили о них: большинство пользователей Windows так или иначе применяют специальные возможности. И хотя некоторые из аспектов специальных возможностей несложно добавить позднее, добавление атрибута aria-* в разметку лучше выполнить раньше.

    В лекции 6 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой" мы так же увидим, как выделить строки (в том числе - метки ARIA) из нашей разметки, JavaScript и даже из манифеста и разместить их в ресурсном файле. Возможно, вы захотите сделать это ранее, поэтому посмотрите раздел "Подготовка к локализации" в этой лекции для того, чтобы узнать подробности. Однако обратите внимание на то, что в Blend разрешение ресурсов нормально не работает, поэтому вам может захотеться сначала выполнить основные настройки внешнего вида приложений, а уже потом прилагать усилия к созданию ресурсных файлов.

    Стилизация в Blend

    В данный момент, учитывая, что вы обратили должное внимание на чтение сносок, Blend отображает реальный вид приложения, который, очевидно, нуждается в стилизации, как и любой исходный каркас приложения. Посмотрите на Рис. 2.10.

    (рис 2.10) Приложение в Blend без стилизации, отображается в виде, который похож на тот, который виден в имитаторе. Если изображение taphere.png не отображается после его добавления, используйте команду меню Вид > Обновить (View > Refresh)

    Закладки около верхнего левого угла окна программы дают вам доступ к файлам вашего проекта, к Активам (Assets), таким, как элементы управления, которые вы можете добавить в ваш пользовательский интерфейс, и средство просмотра для всех правил стилей (Style Rules), определенных в текущем окружении. В левой нижней части присутствует область Динамическая DOM (Live DOM), которая позволяет вам просматривать элементы в иерархии, и закладка Устройство (Device), которая позволяет вам задавать ориентацию, разрешение экрана и состояние просмотра. Щёлкая на элементе в области Динамическая DOM (Live DOM), вы выделяет его в монтажной панели, так же, как щелчок по элементу в монтажной панели, выделяет его в области Динамическая DOM (Live DOM).

    В правой части вы видите то, с чем близко подружитесь: области Атрибуты HTML (HTML Attributes) и Свойства CSS (CSS Properties). Последняя отображает в верхней своей части все источники стилей, которые были применены к выделенному элементу и точное расположение этих стилей (вечная головная боль при работе с CSS). То, что выбрано в данной области. помните, определяет, куда будут записаны изменения, внесенные в панель свойств ниже, поэтому очень внимательно следите за тем, что именно вы выделяете.

    Теперь, чтобы привести нашу исходную страницу к виду, напоминающему каркас приложения, нам нужно поработать с элементами и создать необходимые селекторы и стили. Для начала, я рекомендую создать сетку из одной ячейки (1х1) в теле (body) страницы, так как это улучшит отображение контента на монтажной панели Blend. Поэтому, добавьте display: -grid; -ms-grid-rows: 1fr; -ms-grid-columns: 1fr; в default.css для данного элемента.

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

  • Установите позицию вставки правила стиля в виде жёлто-оранжевой линии на закладке Правила стилей (Style Rules) в Blend. Это точно определяет, где именно будет создано новое правило.
  • Щёлкните правой кнопкой мыши по элементу, который вы хотите стилизовать в панели Динамическая (Live DOM) и выберите команду Создать правило стиля на основе ID элемента (Create Style Rule From Element Id) или команду Создать правило стиля на основе класса элемента (Create Style Rule From Element Class). Примечание. Если оба эти варианта не активны, перейдите на панель Атрибуты HTML (HTML Attributes) (в верхней правой части окна) и добавьте ID, класс, или и то и другое. В противном случае вам придётся вручную править таблицы стилей для управления стилями (особенно в случае с встроенными стилями), так что это избавит вас от сложностей в будущем. Данные действия приведут к созданию нового правила стиля в таблице стилей приложения (в default.css). В панели свойств CSS, в правой части экрана, найдите правило, которое было создано и добавьте необходимые свойства стиля в панель, которая расположена ниже.
  • Повторите эти действия для остальных элементов.
  • Так, для элемента div mainContent мы создаем правило из Id и настраиваем его, задавая display: -ms-grid;-ms-grid-columns: 1fr; и -ms-grid-rows: 128px 1fr 60px;. (Рис. 2.11) Эти действия позволят нам создать базовые вертикальные области каркаса приложения. Обычно, вам не захочется устанавливать правые или левые поля прямо в данной сетке, так как нижняя часть часто имеет горизонтально прокручиваемое содержимое, которое выступает за левый и правый края. В нашем случае, мы можем использовать одну сетку, но вместо этого мы добавим эти поля во вложенной сетке внутри элементов заголовка и раздела.

    (рис 2.11) Установка свойств сетки для элемента div mainContent. Обратите внимание на то, как флаг Просматривать только заданные свойства (View Set Properties Only) (в верхней правой части) упрощает просмотр того, какие стили устанавливаются для текущего правила. Кроме того, обратите внимание, как на монтажной панели (Artboard) отмечены столбы и строки сетки, в том числе - с помощь слайдеров (обведены) для управления строками и столбцами непосредственно на монтажной панели.

    Показ работы над стилями, настройки различных уровней разметки и подходящих стилей для медиазапросов, соответствующих различным состояниям просмотра, лучше всего выглядит на видео. В частности, в файле Video 2-2 (оно находится среди дополнительных данных к курсу) вы можете увидеть этот процесс, начиная с создания проекта, настройки стилей для различных состояний просмотра, до переход в Visual Studio (для этого нужно щёлкнуть правой кнопкой проект в Blend и выбрать команду Изменить в Visual Studio (Edit In Visual Studio)) и запуска приложения в имитаторе для того, чтобы убедиться в том, что всё настроено верно. Кроме того, в видео вы можете оценить объем времени, который нужен для работы со стилями, если вам хорошо знакомы инструменты разработки.

    В результате всех этих действий вид программа в имитаторе соответствует ранее разработанному каркасу, смотрите рисунки 2.12., 2.13., 2.14. - и все настройки стилей полностью включены в соответствующие медиа-запросы файла default.css. Гораздо важнее то, что Blend отображает нам результаты работы в реальном времени, тем самым сохраняя огромное количество времени в сравнении с тем, если бы нам нужно было, после правок, внесенных в CSS, каждый раз запускать приложение - уверен, вы знакомы с этим неприятным процессом! (И экономия времени даже больше с Интерактивным режимом; обратитесь к видеофайлу Video 4-1, который находится среди дополнительных материалов к лекции 4, "Элементы управления, их стилизация и привязка данных").

    (рис 2.12) Полноэкранный альбомный режим просмотра (рис 2.13) Заполняющий режим просмотра (только для альбомного режима) (рис 2.14) Режим прикрепленного просмотра (только для альбомного режима) и полноэкранный портретный режим; они показаны в пропорциональном масштабе

    Добавление кода

    Завершим реализацию приложения в Visual Studio. Щёлкните правой кнопкой по имени проекта на панели Проекты (Projects) в Blender и выберите команду Изменить в Visual Studio (Edit In Visual Studio), если вы этого еще не сделали. Обратите внимание на то, что если ваш проект уже загружен в Visual Studio, когда вы переходите в эту среду, вы (по умолчанию) увидите предложение перезагрузить измененные файлы. Ответьте утвердительноС другой стороны, обратите внимание на то, что Blend не сохраняет файлы автоматически при входе в Интерактивный режим (Interactive Mode) и выходе из него. Если вы сделали изменения в тех же самых файлах, открытых в Visual Studio, перешли в Blend и перезагрузили файлы, вы можете потерять изменения. В данный момент у нас есть макет приложения и стили для всех необходимых режимов просмотра, и мы можем не беспокоиться о коде, за исключением внесения в него небольших улучшений, о которых мы скоро поговорим.

    Что это означает, так то, что, по большей части, мы можем просто написать код нашего приложения для разметки, но не для разметки со стилизацией, что, конечно, является наилучшим подходом при работе с HTML/CSS. Вот возможности, которые мы сейчас реализуем:

  • Элемент управления карт Bing в разделе Местоположение (Locations) показывает пользователю его текущее расположение. Мы просто показываем эту карту автоматически, здесь нет элемента управления, который запускает этот процесс.
  • Используя API WinRT для работы с камерой, мы получаем фотографию в ответа на прикосновение к элементу img Photo.
  • Передаем фотографию и данные о местоположении чудо-кнопке Общий доступ, когда пользователь активирует её.
  • На Рис. 2.15 показано, на что будет похоже приложение, когда мы завершим работу.

    (рис 2.15) Готовое приложение "Here my am!" (хотя здесь я уменьшил масштаб карты, чтобы вы не могли точно назвать место, где я живу!)

    Создание карты с информацией о текущем местоположении

    Для отображения карты мы используем веб-элемент управления карт Bing, экземпляр которого создан на странице map.html, которая загружена в элемент iframe главной страницы. Страница загружает скрипт элемента управления карт Bing из удалённого источника и исполняется в веб-контексте. Обратите внимание на то, что мы, кроме того, можем воспользоваться SDK для карт Bing (лекции 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    Таким образом, разместим файл map.html в папке html. Для этого щёлкните правой кнопкой мыши по проекту, выберите команду Добавить > Создать папку (Add > New Folder), введите для неё имя html. Затем щёлкните правой кнопкой по этой папке, выберите команду Добавить > Создать элемент (Add > New Item) и выберите HTML-страницу (HTML Page). Когда новая страница отобразится на экране, замените её содержимое на следующееОбратите внимание на то, что вы должны заменить значение параметра credentials в функции init на собственный ключ, полученный на https://www.bingmapsportal.com/ :

    <!DOCTYPE html>
    <html>
    <head>
    <title>Map</title>
    <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
    
    <script type="text/javascript">
    //Глобальные переменные
    var map = null;
    
    document.addEventListener("DOMContentLoaded", init);
    window.addEventListener("message", processMessage);
    
    //Функция для преобразования строки к синтаксису { functionName: ..., args: [...] }
    //в вызове именованной функции с такими аргументами. Основана на стандартном
    //диспетчере, который позволяет коду в iframe быть вызванным посредством
    //postMessage. 
    function processMessage(msg) {
    //Проверяет данные и источник (в данном случае - страницу, работающую в локальном
    //контексте)
    if (!msg.data || msg.origin !== "ms-appx://" + document.location.host) {
    return;
    }
    
    var call = JSON.parse(msg.data);
    
    if (!call.functionName) {
    throw "Message does not contain a valid function name.";
    }
    
    var target = this[call.functionName];
    
    if (typeof target != 'function') {	
    throw "The function name does not resolve to an actual function";
    }	
    	
    return target.apply(this, call.args);	
    }	
    
    
    function notifyParent(event, args) {	
    //Добавляет имя события к аргументам обекта и преобразует в строку в
    //качестве сообщения.
    args["event"] = event;	
    window.parent.postMessage(JSON.stringify(args),	
    "ms-appx://" + document.location.host);	
    }	
    
    
    
    //Создает карту (хотя пространство имен не может быть определено без возможности связи)
    function init() {	
    if (typeof Microsoft == "undefined") {	
    return;	
    }	
    
    map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {
    //Замените эти учетные данные на свои, полученные на 
    //http://msdn.microsoft.com/en-us/library/ff428642.aspx 
    credentials: "...",
    //zoom: 12,
    mapTypeId: Microsoft.Maps.MapTypeId.road
    });
    }
    
    function pinLocation(lat, long) {
    if (map === null) {
    throw "No map has been created";
    }
    
    var location = new Microsoft.Maps.Location(lat, long);
    var pushpin = new Microsoft.Maps.Pushpin(location, { draggable: true });
    
    Microsoft.Maps.Events.addHandler(pushpin, "dragend", function (e) {	
    var location = e.entity.getLocation();	
    notifyParent("locationChanged",	
    { latitude: location.latitude, longitude: location.longitude });
    });	
    
    map.entities.push(pushpin);	
    map.setView({ center: location, zoom: 12, });
    return;	
    }	
    
    function setZoom(zoom) {	
    if (map === null) {	
    throw "No map has been created";
    }	
    
    map.setView({ zoom: zoom });
    }
    </script>
    </head>
    <body>
    <div id="mapDiv"></div>
    </body>
    </html>

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

    В верхней части страницы вы можете видеть ссылку на удалённый скрипт элемента управления карт Bing. Мы можем здесь ссылаться на удалённые скрипты, так как страница загружается в веб-контексте внутри элемента iframe (ms-appx-web:// в default.html). Затем вы можете видеть, как функция init вызывается DOMContentLoader и создаёт элемент управления карты. Далее, у нас есть еще пара методов, pinLocation и setZoom, которые, если понадобятся, могут быть вызваны из основного приложения.

    Конечно, так как эта страница загружена в iframe в веб-контексте, мы не можем просто вызвать эти функции напрямую из кода нашего приложения. Вместо этого мы используем функцию HTML5 postMessage, которая вызывает событие message в iframe. Это важный момент: локальный и веб-контексты разделены, поэтому произвольный веб-контент не может управлять приложением или получать доступ к API WinRT. Эти два контекста разделены границей между приложением и веб'ом, которую может пересечь лишь postMessage.

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

    Для того, чтобы посмотреть на то, как это работает, взглянем на то, как мы вызываем pinLocation из default.js. Для того, чтобы выполнить этот вызов, нам нужны некоторые координаты, которые мы можем получить из API для определения местоположения (Geolocation) WinRT. Мы делаем это в обработчике события onactivated, поэтому местоположение пользователя задаётся при старте приложения (и сохраняется в переменной lastPosition позже для организации общего доступа):

    //Поместите это после строки: var activation = Windows.ApplicationModel.Activation;
    var lastPosition = null;
    
    
    //Поместите это после args.setPromise(WinJS.UI.processAll());
    var gl = new Windows.Devices.Geolocation.Geolocator();
    
    gl.getGeopositionAsync().done(function (position) {	
    //Сохраним для общего доступа	
    lastPosition = { latitude: position.coordinate.latitude,
    longitude: position.coordinate.longitude };	
    
    callFrameScript(document.frames["map"], "pinLocation", [position.coordinate.latitude, position.coordinate.longitude]);
    });

    Здесь callFrameScript - это просто небольшая вспомогательная функция, которая превращает целевой элемент, имя функции и аргументы в соответствующий вызов posMessage:

    //Поместите это перед app.start();	
    function callFrameScript(frame, targetFunction, args) {	
    var message = { functionName: targetFunction, args: args };	
    frame.postMessage(JSON.stringify(message), "ms-appx-web://" + document.location.host);
    	}

    Некоторые замечания по этому коду. Для того чтобы получить координаты, вы можете использовать API WinRT для определения местоположения или API HTML5 для определения местоположения. Они почти одинаковые, с небольшими различиями, описанными в лекции 3 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript", "Ввод данных и сенсоры", во врезке: "Определение местоположения в HTML5". Это API присутствует в WinRT, так как другие поддерживаемые языки (C# и C++) не имеют доступ к API определения местоположения HTML5. Мы, в этом курсе, сосредоточены на API WinRT, поэтому мы просто используем функции в пространстве имен Windows.Devices.Geolocation.

    Далее, в качестве второго параметра postMessage, вы можете видеть комбинацию из ms-appx[-web]:// и document.location.host. Это означает: "текущее приложение из локального [или веб] контекста", которое является подходящим источником сообщения. Обратите внимание на то, что мы используем то же самое значение для того, чтобы проверить источник сообщения при его получении: код в map.html проверяет, пришло ли сообщение из локального контекста приложения, тогда как код в default.js проверяет, что сообщение пришло из веб-контекста приложения. всегда будьте уверены в том, что соответствующим образом проверяете источники сообщения; посмотрите материал "Разработка безопасных приложений" (http://msdn.microsoft.com/library/windows/apps/hh849625.aspx).

    Наконец, вызов getGeoPositionAsync содержит интересную конструкцию, где мы делаем вызов и используем внутри него цепочку из функции done, аргумент которой - еще одна функция. Это - весьма распространённый подход, который мы можем видеть, работая с API WinRT, для любого API, которому может потребоваться более 50 мс для завершения асинхронной операции. Подобное решение было принято так, что использование API ведет к созданию быстрых и динамичных приложений по умолчанию.

    В JavaScript подобные API возвращают то, что называется promise-объектом, он представляет результаты, которые будут получены когда-нибудь в будущем. Каждый такой объект имеет метод done, первый аргумент которого - функция, которая будет вызвана по завершении операции, обработчик завершения (completed handler). В учебном курсе мы еще коснёмся данной темы, в частности, поговорим о функции then, которая похожа на done, но поддерживает дальнейшее объединение функций в цепочку (лекция 3) и о том, как promise-объекты в более общем виде используются в асинхронных операциях (лекция 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Аргумент, который передается обработчику завершения содержит результат асинхронного вызова, в нашем случае это объект Маркер местоположения можно перемещать, однако сейчас это не окажет никакого влияния на наше приложение. Смотрите раздел "Исключительное доверие: Принимаем сообщения из iframe" ниже для того, чтобы узнать, как мы можем получить сведения об изменении местоположения с карты.

    Еще одно, последнее, примечание по асинхронным API. Внутри API WinRT все асинхронные функции имеют "Async" в своих именах. Так как подобная практика не принята в среде JavaScript или DOM API, асинхронные функции внутри WinJS не используют данный суффикс. Другими словами, WinRT создана нейтральной по отношению к языкам программирования, а WinJS разработана с учетом языковых соглашений, характерных для JavaScript.

    О, подождите, манифест!

    Сейчас вы уже могли испытать тот код, который приведен выше, и столкнуться с исключением "Доступ запрещен" при попытке вызова getGeoPositionAsync. Почему это так? Исключение говорит о том, что мы не указали возможность Расположение (Location) в манифесте. Без включения этой возможности, вызов вроде этого, зависящий от возможности, вернет исключение.

    Если вы запускаете пример в отладчике, это исключение покажет диалоговое окно. Если вы запускаете его вне отладчика - с плитки на Начальном экране - вы увидите, что приложение просто прекратило работать, не показав ничего, кроме экрана-заставки. Это - обычное поведение для необработанных исключений. Для того, чтобы предотвратить подобное поведение, добавим функцию для обработки ошибок в качестве второго параметра метода done асинхронного promise-объекта:

    gl.getGeopositionAsync().done(function (position) {
    //...	
    }, function(error) {	
    console.log("Unable to get location.");	
    });

    Функция console.log записывает строку в окно Консоли JavaScript (JavaScript Console) в Visual Studio, а это, очевидно, хорошая идея. Сейчас запустите приложение вне отладчика, и вы увидите, что оно запустилось, так как исключение теперь признано "обработанным". В отладчике установите точку останова на строку console.log и точка останова сработает после того, как появится исключение и вы нажмете Далее (Continue). (Пока это всё, что мы делаем с появляющимися ошибками; в лекции 1 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript" мы добавим более подходящее сообщение и команду повтора действия).

    Если диалоговое окно исключения вам надоело, вы можете управлять тем, информацию о каких исключениях показывать во всплывающих окнах с помощью диалогового окна Отладка > Исключения (Debug > Exceptions), показанного на Рис. 2.16, в разделе Исключения JavaScript времени выполнения (JavaScript Runtime Exceptions). Если вы снимете флажки в колонке Необработанное пользовательским кодом (User-unhandled), вы не увидите диалоговое окно, когда происходит то или иное исключение.

    (рис 2.16) Исключения JavaScript времени выполнения в диалоговом окне Отладка > Исключения (Debug > Exceptions) в Visual Studio

    Вернемся к возможностям: для того, чтобы это приложение правильно себя вело, откройте package.appmanifest вашего проекта, выберите закладку Возможности (Capabilities) и включите Расположение (Location), как показано на Рис. 2.17.

    (рис 2.17) Установка возможности Расположение (Location) в редакторе манифеста Visual Studio. (Обратите внимание на то, что Blend поддерживает правку манифеста лишь в качестве XML-файла)

    Теперь, даже если мы объявили возможность, геолокация всё еще требует разрешения пользователя, как было указано в лекции 1. При первом запуске приложения с установленной возможность вы увидите всплывающее окно, похожее на то, что изображено на Рис. 2.18. Если пользователь запретит доступ в этом окне, обработчик ошибки снова будет запущен, так как API снова выдаст исключение запрета доступа.

    (рис 2.18) Типичное окно, позволяющее узнать мнение пользователя, отражающее пользовательскую цветовую схему, которое появляется при первой попытке приложения вызвать API, доступ к которому осуществляется через брокера (в данном случае - геолокационное API). Если пользователь запретит доступ, API выдаст ошибку, но позже пользователь может изменить решение в панели Параметры > Разрешения (Settings > Permissions).

    Врезка: как сбросить информацию о решении пользователя для целей тестирования?

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

    Обратите внимание на то, что когда пользователь изменяет настройки разрешений, приложение никак не оповещается об этом. Приложение может обнаружить это изменение, лишь попытавшись использовать API снова. Мы вернемся к этому в лекции 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    Получение фотографии с камеры

    Хоть это и необычно, я надеюсь, что идея добавить описание получений фотографий с камеры в раздел "быстрый старт", заставит вас сомневаться во вменяемости автора. Не потребуется ли для этого огромного количества кода? Да, так было, но в Windows 8 это не так. Все сложные особенности захвата данных с камеры отлично инкапсулированы внутри API Windows.Media.Capture, так что, в итоге, мы можем добавить в приложение эту возможность с помощью нескольких строк кода. Это хороший пример того, как небольшой динамичный код, наподобие JavaScript комбинируется с отлично спроектированными компонентами WinRT - и то и другое в системе, и тем и другим вы можете пользоваться - создавая мощный союз.

    Для того, чтобы реализовать эту возможность, сначала нам нужно вспомнить, что камера, как и GPS-приёмник, относится к устройствам, от которых может пострадать приватность пользователя, поэтому возможность, связанную с ней, так же нужно объявлять в манифесте, Рис. 2.19.

    (рис 2.19) Возможность, связанная с камерой в редакторе манифеста Visual Studio

    При первом использовании камеры во время выполнения приложения, вы увидите еще одно диалоговое окно, запрашивающее разрешение пользователя, Рис. 2.20.

    (рис 2.20) Всплывающее окно для получения разрешения пользователя на применение камеры. Вы можете в любой момент изменить эту настройку в панели Параметры > Разрешения (Settings > Permissions)

    Теперь нам нужно настроить элемент img для того, чтобы он мог реагировать на жест прикосновения. Для этого нам нужно просто добавить прослушиватель события click, который срабатывает для любых способов ввода (сенсорный интерфейс, мышь, перо), как мы увидим в лекции 3 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    var image = document.getElementById("photo");
    image.addEventListener("click", capturePhoto.bind(image));

    Здесь мы указываем capturePhoto в качестве обработчика события и используем функциональность объектного метода bind для того, чтобы объект this внутри capturePhoto был напрямую связан с элементом img. В результате, этот обработчик может быть использован для любого количества элементов, так как он не ссылается на DOM.

    //Расположите это под var lastPosition = null;
    var lastCapture = null;
    
    
    //Расположите это после callFrameScript	
    function capturePhoto() {	
    //В соответствии с вызовом .bind() в addEventListener, "this" будет элементом image,
    //но нам нужна копия для асинхронно завершившегося обработчика ниже.	
    var that = this;	
    
    var captureUI = new Windows.Media.Capture.CameraCaptureUI();
    
    //Показывает, что мы хотим получить PNG-изображение не больше, чем целевой элемент -	
    //пользовательский интерфейс автоматически обрежет изображение под этот размер	
    captureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
    captureUI.photoSettings.croppedSizeInPixels =	
    { width: this.clientWidth, height: this.clientHeight };	
    
    captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .done(function (capturedFile) {
    //Убедитесь, что проверили, подходит ли вам возвращенный элемент: он может содержать null, если
    //пользователь отменил действие.
    if (capturedFile) {
    lastCapture = capturedFile; //Сохраняем для целей Общего доступа (Share)
    that.src = URL.createObjectURL(capturedFile, {oneTimeOnly: true});
    }
    }, function (error) {
    console.log("Unable to invoke capture UI.");
    });
    }

    Нам необходимо создать локальную копию this внутри обработчика click, так как, как только мы оказываемся внутри функции завершения асинхронного запроса (посмотрите функцию внутри captureFileAsync.done) мы оказываемся в новой области видимости и объект this изменяется. Принято такую копию this называть that. Берем это?

    Для того чтобы запустить интерфейс камеры, нам лишь нужно создать экземпляр Windows.Media.Capture.CameraCaptureUI с ключевым словом new (обычный способ создания экземпляров динамических объектов WinRT), настроить его на желаемый формат и размер изображения (это одни из многих других возможных параметров, которые обсуждаются в лекции 4 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript") и вызвать captureFileAsync. Здесь будет произведена проверка манифеста, и, если необходимо, будет запрошено разрешение пользователя.

    Это асинхронный вызов, поэтому мы используем .done в конце с обработчиком завершения, который в данном случае принимает объект Параметр {oneTimeOnly: true} показывает, что URI не подлежит повторному использованию и должен быть аннулирован с помощью URL.revokeObjectURL, когда он больше не используется, как в случае, когда мы заменяем img.src на новое изображение. Без использования данного подхода мы столкнёмся с утечкой памяти при отображении каждого нового изображения. Если ранее вы использовали URL.createObjectURL, вы увидите, что второй параметр теперь представляет собой неупорядоченный набор свойств (property bag), что объединяет его с наиболее свежими спецификациями W3C!

    Обратите внимание на то, что captureFileAsync вызовет обработчик завершения, если пользовательский интерфейс был успешно отображен, но пользователь нажал кнопку Назад и фото не было сделано. Именно поэтому присутствует дополнительная проверка правильности captureFile. Обработчик ошибки в promise-объекте, в свою очередь, сначала перехватит ошибки запуска пользовательского интерфейса, но обратите внимание на то, что при отсутствии разрешения пользователя на работу с камерой, сообщение об этом появится непосредственно в пользовательском интерфейсе камеры (Рис. 2.21), поэтому нет необходимости иметь обработчик ошибки для этих целей в данном API. В большинстве случаев, однако, вам понадобится соответствующий обработчик ошибок для асинхронных вызовов.

    (рис 2.21) Сообщение в пользовательском интерфейсе камеры, когда пользователь не разрешил доступ к ней (слева); вы можете изменить разрешения посредством панели Разрешения чудо-кнопки Параметры (Settings) (справа)

    Делимся удовольствием!

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

    Windows 8 вместо этого предложила понятие контракта Общий доступ (Share), который используется для применения возможностей чудо-кнопки Общий доступ (Share) во всех приложениях, реализующих данный контракт. Когда вы, находясь в приложении, нажимаете на чудо-кнопку Общий доступ, Windows запрашивает у приложения исходные (source) данные. Затем система проверяет данные и генерирует список целевых (target) приложений, которые способны воспринимать данные в этом формате (в соответствии с манифестом), и отображает список приложений в панели чудо-кнопки Общий доступ. Когда пользователь выбирает целевой приложение, это приложение активируется и ему передаются исходные данные. Коротко говоря, контракт - это промежуточная абстракция, находящаяся между двумя приложениями, таким образом, приложение-источник и приложение-приемник никогда не нуждаются в информации друг о друге.

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

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

    Этот запрос приходит через событие Так как мы, когда приложение выполняется, постоянно прослушиваем событие datarequested и добавляем прослушиватель события лишь один раз, нам не нужно беспокоиться о том, чтобы удалять его, вызывая removeEventListener. Подробности смотрите в разделе "События WinRT и removeEventListener" в лекции 3. Для начала, нам лишь нужно установить соответствующий прослушиватель события, разместив нижеприведенный код в событии activated в файле default.js после установки прослушивателя для события click элемента img:

    var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
    dataTransferManager.addEventListener("datarequested", provideData);

    Идея текущего представления (current view) заключается в том, что это то, что мы видим в появляющихся время от времени областях. Это отражает то, что приложение может быть запущено по разным причинам - таким, как обслуживание контракта - и, таким образом, предоставлять пользователю различные страницы или представления. Эти представления (не связанные с режимами просмотра, такими, как прикрепленный, заполняющий и другие) могут быть активны одновременно. Для обработки этих состояний убедитесь в том, что ваш код реагирует на них, определенные API возвращают объекты, соответствующие текущему представлению приложения, как мы видим здесь.

    В данном событии обработчик принимает объект Windows.ApplicationModel.DataTransfer.DataRequest в параметрах события (e.request), которые хранятся в объекте DataPackage (e.request.data). Для того чтобы сделать данные доступными для целей общего доступа, вы заполняете пакет данных (data package) информацией в доступном вам формате. (Мы сохраняем данные в lastPosition и lastCapture.) В нашем случае, мы убеждаемся в том, что имеем фотографию и информацию о местоположении и заполняем свойства текста и изображения (если вы хотите получить карту от сервиса Bing для передачи её в другое приложение, посмотрите материал "Получение статической карты" (http://msdn.microsoft.com/library/ff701724.aspx):

    //Поместите это после capturePhoto 
    function provideData(e) {
    var request = e.request;
    var data = request.data;
    
    if (!lastPosition || !lastCapture) {
    //Нечего передавать, поэтому выходим
     return;
    }
    
    data.properties.title = "Here My Am!";
    
    data.properties.description = "At ("	
    + lastPosition.latitude + ", " + lastPosition.longitude + ")";	
    	
    //Передавая изображение, добавляем миниатюру	
    var streamReference =	
    Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(lastCapture);
    data.properties.thumbnail = streamReference;	
    // Рекомендовано использовать и setBitmap и setStorageItems при передаче отдельного изображения
    //так как целевое приложение может поддерживать лишь что-то одно.
    
    //Поместим файл изображения в массив и передадим его setStorageItems data.setStorageItems([lastCapture]);
    
    //Методу setBitmap требуется RandomAccessStream. data.setBitmap(streamReference);
    }

    Последняя часть этого кода представляет собой стандартную реализацию возможности по передаче изображения из файла (которое находится в lastCapture). Я взял большую часть этого кода из примера "Приложение-источник для общего доступа", (лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    С этим последним дополнением, и с подходящим приложением-приемником (таким, как в примере "Приложение-цель для общего доступа", (http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782), как показано на Рис. 2.22), сейчас мы получили весьма функциональное приложение, которое состоит из 35 строк HTML-кода, 125 строк CSS и 100 JavaScript-строк!

    (рис 2.22) Передача данных (обезьяна увидела, обезьяна сделала!) в приложение из примера реализации целевого приложения Windows SDK. Целевое приложение частично перекрывает текущее приложение, таким образом, пользователь никогда не потеряет контекст приложения

    Исключительное доверие: Принимаем сообщения из iframe

    Вот еще один фрагмент кода, который я включил в программу "Here My Am!" для того, чтобы завершить пример базового взаимодействия между приложением и iframe: возможность отправлять сообщения из iframe назад, в приложение. В нашем случае, мы хотим знать, когда изменилось положение маркера местоположения для того, чтобы обновить lastPosition.

    Для начала, вот простая стандартная функция, которую я добавил в map.html для того, чтобы включить в неё подходящий вызов postMessage, направленный к приложению, из iframe:

    function function notifyParent(event, args) {
    Добавляем имя события к объекту, содержащему аргументы, и конвертируем в строку для формирования сообщения
    args["event"] = event;	
    window.parent.postMessage(JSON.stringify(args), "ms-appx://" + document.location.host);

    Эта функция берет имя события, добавляет его к объекту, содержащему параметры, конвертирует всё это в строку и отправляет результат туда, откуда её вызвали.

    Когда маркер перетащили, карта Bing генерирует событие dragend, к которому мы прикрепим обработчик и обработаем событие в функции setLocator сразу после того, как маркер был создан (так же в map.html):

    var pushpin = new Microsoft.Maps.Pushpin(location, { draggable: true });
    
    Microsoft.Maps.Events.addHandler(pushpin, "dragend", function (e) {	
    var location = e.entity.getLocation();	
    notifyParent("locationChanged",	
    { latitude: location.latitude, longitude: location.longitude });
    });

    Вернемся назад, в default.js (то есть - в приложение) и добавим прослушиватель для входящих messages (сообщений) внутрь app.onactivated:

    window.addEventListener("message", processFrameEvent);

    Обработчик processFrameEvent ищет в сообщении информацию о событии и поступает соответствующим образом:

    function processFrameEvent (message) {	
    //Проверяем данные и источник (в нашем случае это - страница из веб-контекста)	
    if (!message.data || message.origin !== "ms-appx-web://" + document.location.host) {
    return;	
    }	
    
    if (!message.data) {
    return;
    }
    
    var eventObj = JSON.parse(message.data);
    
    switch (eventObj.event) {	
    case "locationChanged":	
    lastPosition = { latitude: eventObj.latitude, longitude: eventObj.longitude };
    break;	
    
    default:
    break;
    }
    };

    Ясно, что здесь больше кода, чем нам нужно для того, чтобы обработать одно сообщение или событие из iframe, но я хочу предоставить вам универсальное решение, которое вы сможете использовать в своих приложениях и в других случаях.

    Другие шаблоны

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

    Приложение с фиксированным макетом (Fixed Layout Template)

    "Проект приложения для Магазина Windows, которое масштабируется с использованием макета с фиксированными пропорциями" (Описание из Blend/Visual Studio).

    Недавно мы видели приложение, которое подстраивается под изменения отображаемой области, изменяя свой макет. В "Here My Am!" мы использовали CSS-сетку с автоматически настраиваемыми областями (значения 1fr в строках и столбцах). Такой подход хорошо работает для приложений с содержимым, которое хорошо поддаётся масштабированию и для приложений, которые могут показывать дополнительный контент, такой, как заголовки новостей или результаты поиска, когда у них больше места.

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

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

    <body>	
    <div data-win-control="WinJS.UI.ViewBox">
    <div class="fixedlayout">	
    <p>Content goes here</p>	
    </div>	
    </div>	
    </body>

    В файле default.css вы можете видеть элемент body, которому задан стиль "резинового" блока CSS, центрированного на экране, и элемент fixedLayout, установленный на размер 1024х768 (минимальный размер окон полноэкранных альбомных приложений и приложений в режиме заполняющего просмотра). Размещая содержимое внутри дочернего элемента div, который принадлежит элементу ViewBox, вы можете быть уверены в том, что работаете с этими фиксированными размерностями. ViewBox автоматически настроит масштаб того, что находится внутри, и, при необходимости, добавит пустые пространства сверху и снизу или справа и слева для сохранения пропорций.

    Обратите внимание на то, что подобные приложения могут не поддерживать интерактивный прикрепленный режим. В игры, например, невозможно играть при уменьшении размеров их окна. В подобном случае приложение может просто поставить игру на паузу и попытаться выйти из прикрепленного режима, если пользователь пытается продолжить игру. Мы вернемся к этому в лекции 6.

    Приложение навигации (Navigation Template)

    "Проект приложения для Магазина Windows, которое содержит предопределенные элементы управления для навигации" (Описание из Blend/Visual Studio).

    Шаблон Приложение навигации построен на базе шаблона Пустое приложение путём добавления к нему системы навигации по страницам. Как было сказано в лекции 1, приложения для Магазина Windows, написанные на JavaScript, лучше реализовать в виде единственной HTML-страницы, выступающей в роли контейнера, в который динамически загружаются другие страницы. Это позволяет организовать плавные переходы (так же, как и анимации) между этими страницами и сохранить скриптовый контекст.

    Этот шаблон, и другие оставшиеся, использует элемент управления Page Navigator, который облегчает загрузку (и отправку) страниц таким способом. Вам нужно лишь создать сравнительно простую структуру для описания каждой страницы и её поведения. Мы рассмотрим это в лекции 3.

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

    Приложение таблицы (Grid Template)

    "Трехстраничный проект приложения для Магазина Windows, которое осуществляет переходы между группами элементов, расположенных в сетке. Сведения о группах и элементах отображаются на выделенных страницах" (Описание из Blend/Visual Studio).

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

    В дополнение к навигации, шаблон Приложение таблицы показывает пример управления коллекциями данных посредством класса WinJS.Binding.List. Эту тему мы подробно рассмотрим в лекции 5, "Коллекции и элементы управления для коллекций". Кроме того, он предоставляет структуру для создания панели приложения и показывает, как упростить поведение приложения в прикрепленном режиме.

    Имя шаблона, кстати, получилось от особого табличного (сеточного) макета, который используется для отображения коллекций данных, а не от CSS-сетки (CSS grid).

    Приложение с разделением (Split Template)

    "Двухстраничный проект приложения для Магазина Windows, которое осуществляет переходы между группированными элементами. Первая страница позволяет выбрать группу, а вторая отображает список элементов вместе со сведениями о выбранном элементе" (Описание из Blend/Visual Studio).

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

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

    Что мы только что изучили:

  • Как создать новое приложение для Магазина Windows с использованием шаблона Пустое приложение.
  • Как запустить приложение внутри локального отладчика и внутри имитатора, о роли отладки на удалённой машине.
  • Функции имитатора, которые включают возможность симулировать касания, устанавливать состояния просмотра, менять разрешение и плотность пикселей.
  • Основные структуры проекта приложения для Магазина Windows, в том числе - ссылки на WinJS.
  • Основную структуру активации приложения посредством события WinJS.Application.onactivated
  • Роль и полезность проектирования каркаса приложения при разработке приложения, включая важность проектирования интерфейсов для всех состояний просмотра, где особую важность приобретает видимость элементов и макет.
  • Мощь Blend для Visual Studio для быстрой и эффективной стилизации разметки приложения. Blend, кроме того, является отличным инструментом для отладки CSS.
  • Как безопасно использовать веб-контент (такой, как карты Bing) внутри веб-контекста iframe и как организовать обмен данными между подобной страницей и локальным контекстом приложения, используя метод postMessage.
  • Как использовать API WinRT, в особенности асинхронные методы, использующие promise-объекты, как пользоваться определением местоположения и захватом изображений с камеры. Асинхронные операции возвращают promise-объекты, которым вы предоставляете обработчик завершения (и, необязательно, обработчики ошибок и этапов выполнения задания), для методов promise-объектов then или done.
  • Возможности, заявленные в манифесте, определяют, может ли приложение использовать конкретные API WinRT. Исключения возникают, если приложение пытается воспользоваться API, не объявляя соответствующую возможность.
  • Как передавать данные в другие приложения, используя контракт Share (Общий доступ) в ответ на событие datarequested.
  • Виды приложений, поддерживаемые другими шаблонами приложений: Приложение с фиксированным макетом, Приложение навигации, Приложение таблицы и Приложение с разделением.
  • Страницы:

    Файлы к данной лекции Вы можете скачать здесь.

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

    Настоящий быстрый старт: шаблон Пустое приложение

    Конечно, мы должны начать с того, чтобы отдать дань уважения классическому приложению "Hello World". Мы можем сделать это, не написав ни единой строчки кода. Нам лишь нужно создать новое приложение из шаблона в Visual Studio.

  • Запустите Visual Studio Express. Если вы делаете это впервые, вам предложат получить лицензию разработчика. Сделайте это, так как иначе вы не сможете продолжать!
  • Щёлкните Создать проект… (New Project…) в окне Visual Studio или используйте команду меню Файл > Создать проект (File > Create Project)
  • В появившемся диалоговом окне (Рис. 2.1) убедитесь, что выбрали в разделе Шаблоны (Templates), слева, JavaScript и выберите шаблон Пустое приложение (Blank Application) в центральной части окна. Задайте имя (HelloWorld подойдёт), папку и нажмите OK. (рис 2.1) Диалоговое окно Создать проект, использующее светлую тему пользовательского интерфейса. (Смотрите команду меню Сервис > Параметры (Tools > Options) и измените тему в разделе Среда>Общие (Environment>General)). Я использую здесь светлую тему, так как она лучше смотрится на белом фоне страниц
  • После того, как Visual Studio создаст проект, нажмите кнопку Начать отладку (Start Debugging) (или нажмите F5 или выберите команду меню Отладка > Начать отладку (Debug > Start Debugging)). Подразумевая то, что всё у вас установлено верно, вы должны увидеть что-то вроде Рис. 2.2 на своём экране. (рис 2.2) Единственная интересная часть окна приложения HelloWorld. Сообщение - это, как минимум, лучшее приглашение к написанию большего количества кода, чем нужно для вывода стандартного приветствия первого приложения!
  • По умолчанию, Visual Studio запускает отладчик в режиме локального компьютера (local machine), в котором приложение запускается в полноэкранном режиме в вашей операционной системе. В результате мы сталкиваемся с неудобством, когда отладчик скрывается, если только вы не используете систему с несколькими мониторами, когда вы можете открыть Visual Studio на одном мониторе и своё приложение для Магазина Windows - на другом. Посмотрите материал "Выполнение приложений для Магазина Windows на локальном компьютере" (http://msdn.microsoft.com/library/windows/apps/hh441483.aspx) для того, чтобы больше об этом узнать.

    Visual Studio предлагает два других режима отладки, которые можно выбрать из выпадающего списка на панели инструментов (Рис. 2.3), или в меню Отладка > Свойства [Имя приложения] ( Debug > [Appname] Properties), Рис. 2.4.

    (рис 2.3) Параметры отладки в панели инструментов Visual Studio (рис 2.4) Параметры отладки в окне свойств приложения в Visual Studio

    Параметр Удалённый компьютер (Remote Mashine) позволяет вам запускать приложение на другом устройстве, что абсолютно типично при работе с устройствами, которые не способны выполнять настольные приложения, как, например, ARM-устройства (и если вы видите лишь эту опцию в примере проекта, активная платформа решения, возможно, установлена в ARM). Настройка здесь достаточно проста: смотрите материал "Выполнение приложений для Магазина Windows на удаленном компьютере" (http://msdn.microsoft.com/library/windows/apps/hh441469.aspx), и я рекомендую, чтобы вы хорошо с ним ознакомились. Кроме того, если проект не загружен в Visual Studio, меню Отладка предлагает команду Присоединиться к процессу (Attach to process), которая позволяет отлаживать уже запущенные приложения. Смотрите материал "Запуск сеанса отладки (JavaScript)" (http://msdn.microsoft.com/library/windows/apps/hh771032.aspx).

    Имитатор (simulator) так же весьма интересен, а на мой взгляд - самый интересный инструмент, и место, где, по-моему, вы будете проводить очень много времени. Он дублирует ваше окружение внутри новой сессии входа в систему и позволяет вам управлять ориентацией устройства, устанавливать различные разрешения и коэффициенты масштабирования, имитировать события касаний экрана и работать с данными, которые поступили от API определения местоположения. На Рис. 2.5 вы можете видеть приложение Hello World в имитаторе, с отмеченными дополнительными элементами управления. Подробнее об имитаторе вы узнаете далее, хотя вы так же можете захотеть прочесть материал "Выполнение приложений для Магазина Windows на имитаторе" (http://msdn.microsoft.com/library/windows/apps/hh441475.aspx).

    (рис 2.5) Приложение HelloWorld работает в имитаторе, справа добавлены подписи к кнопкам. На самом деле, шаблон "Пустое приложение" оправдывает своё название!

    Поверх остальных окон (Always on top)

    Режим мыши(Mouse pointer)

    Базовый сенсорный режим (Touch emulator)

    Сенсорный режим с жестом сжатия/масштабирования (Emulate touch zooming)

    Сенсорный режим с вращением (Emulate touch rotation)

    Повернуть по часовой стрелке на 90 градусов (Rotate device 90 clockwise)

    Повернуть против часовой стрелки на 90 градусов (Rotate device 90 counter-clockwise)

    Изменить разрешение (Set resolution/scaling)

    Задать положение (Set GPS Coordinates)

    Копирование снимка экрана (Take a screenshot)

    Параметры снимка экрана (Screenshot settings)

    Справка (Help)

    Врезка: Как Visual Studio запускает приложение?

    Visual Studio разворачивает приложение так же, как это происходит при получении приложения из Магазина Windows. Приложение появляется на Начальном экране, где вы можете деинсталлировать его. Деинсталляция очищает папки с данными приложения, сведения о его состояниях, что весьма полезно при отладке.

    Здесь нет ничего необычного: развёртывание можно произвести и с использованием инструментов командной строки. Для того, чтобы увидеть подробности, воспользуйтесь командой Магазин > Создать пакеты приложения (Store > Create App Package) в Visual Studio, выберите Нет в параметре, отвечающем за отправку в Магазин Windows, и вы увидите диалоговое окно, позволяющее вам сохранить пакет приложения там, где вы захотите. В указанной папке вы найдете пакет appx, сертификат безопасности и пакетный файл, который называется Add-AppxDevPackage. Этот файл содержит скрипты PowerShell, которые разворачивают приложение и ресурсы, от которых оно зависит.

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

    Структура проекта Пустое приложение

    Приложение, созданное по шаблону Пустое приложение (Blank App), не имеет большого количества визуальных элементов, оно предоставляет определенную структуру проекта. Вот, что вы можете найти после создания проекта по шаблону, в Обозревателе проектов Visual Studio (Рис. 2.6).

  • default.html Cтартовая страница приложения.
  • <Appname>_TemporaryKey.pfx Файл временной электронной подписи, создаваемый при первом запуске.
  • package.appmanifest Файл-манифест. При открытии этого фйала отображается редактор манифеста Visual Studio (ниже в этой лекции мы рассмотрим его). Я рекомендую вам уделить несколько минут на то, чтобы изучить его. Например, там вы увидите ссылки на изображения, упомянутые ниже, флаг у возможности Интернет (клиент), страницу default.html, указанную как стартовая страница, и различные другие настройки приложения. Мы рассмотрим это в данном учебном курсе; подробности вы можете найти в материалах "Пакеты приложений и их развертывание" (http://msdn.microsoft.com/library/windows/apps/hh464929.aspx) и "Конструктор манифеста" (http://msdn.microsoft.com/library/windows/apps/br230259.aspx). И, если вы хотите просмотреть XML-файл манифеста напрямую, щёлкните по нему правой кнопкой и выберите команду Перейти к коду (View Code).
  • Папка css содержит файл default.css, где вы увидите структуры медиа-запросов для четырёх состояний просмотра, которые следует учитывать всем приложениям. Мы увидим это в действии в следующем разделе и обсудим подробности в лекции 6, "Макет".

    Папка images содержит четыре образца изображения, и если только вы не хотите выглядеть недалёким разработчиком, вы всегда будете менять эти изображения на собственные перед отправкой приложений в Магазин Windows (и, кроме того, создавать масштабированные версии, как мы увидим в лекции 3, "Анатомия приложения и навигация по страницам".

  • logo.png Изображение по умолчанию для стартовой страницы (размер 150х150 пикселей, 100% масштаб)
  • smallogo.png Изображение размером 30х30 для уменьшенной стартовой страницы и для других мест, используемое во время выполнения программы.
  • splashscreen.png Изображение размером 620х300, которое будет показано во время загрузки приложения.
  • storelogo.png Изображение размером 50х50, которое будет показано в Магазине Windows. Оно должно быть частью пакета приложения, однако, не используется во время выполнения программы в Windows.
  • Папка js содержит файл default.js.

    Папка Ссылки (References) указывает на CSS и JS-файлы библиотеки WinJS. Мы можете открыть любой из них для того, чтобы посмотреть, как устроена WinJS. (Обратите внимание на то, что если вы нуждаетесь в поиске по этим файлам, вы должны открыть конкретный файл и выполнять поиск в нём. Поиск по всему проекту или решению в данном случае не поддерживается).

    (рис 2.6) Проект, построенный по шаблону Пустое приложение, полностью раскрыт в Обозревателе решений

    Как можно ожидать, в проекте этого типа не так уж много кода, специфичного для приложения. Например, тело HTML-документа имеет лишь один абзац, который вы можете заменить на "Hello World", если вы чувствуете, что не можете без этого обойтись. Что гораздо важней - так это ссылки на компоненты WinJS: основной файл со стилями (ui-dark.css или ui-light.css), файлы base.js и ui.js:

    <!DOCTYPE html>	
    <html>	
    <head>	
    <meta charset="utf-8">	
    <title>Hello World</title>
    
    <!-- Ссылки WinJS -->	
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet">
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>	
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>	
    
    <!-- Ссылки HelloWorld -->	
    <link href="/css/default.css" rel="stylesheet">
    <script src="/js/default.js"></script>	
    </head>	
    <body>	
    <p>Content goes here</p>	
    </body>	
    </html>

    Как правило, такие ссылки присутствуют всегда (возможно, с ui-light.css) в каждом из HTML-файлов вашего проекта. Двойные // в путях WinJS указывают на библиотеки с разделяемым доступом, а не на файлы в пакете вашего приложения, в то время, как одиночные / указывают на корневой каталог вашего раздела. Помимо этого, всё остальное - это стандартный HTML5, поэтому вы можете свободно добавлять дополнительные HTML-теги и наблюдать за производимым ими эффектом.

    Что касается JavaScript, то default.js просто содержит базовый код активации WinJS, находящийся в событии WinJS.Application.onactivated вместе с заглушкой для события, которое называется WinJS.Application.oncheckpoint:

    (function () { "use strict";
    
    var app = WinJS.Application;
    var activation = Windows.ApplicationModel.Activation;
    
    app.onactivated = function (args) {
    if (args.detail.kind === activation.ActivationKind.launch) {
    if (args.detail.previousExecutionState !==
    activation.ApplicationExecutionState.terminated) {
    // TODO: Это приложение было вновь запущено. Инициализируйте
    // приложение здесь.
    } else {
    // TODO: Это приложение вновь активировано после приостановки.
    // Восстановите состояние приложения здесь.
    }
    args.setPromise(WinJS.UI.processAll());
    }
    };
    
    app.oncheckpoint = function (args) {
    };
    
    app.start();
    })();

    Мы вернемся к checkpoint в лекции 3. Сейчас, вспомните из лекции 1, что приложение может быть активировано различными способами. Это отражено в свойстве args.detail.kind, значения которого принадлежат перечислению Windows.ApplicationModel.Activation.ActivationKind.

    Когда приложение запущено прямо со своей плитки на Начальное экране (или запущено в отладчике, как у нас), вид активации имеет значение launch. Как мы увидим далее, другие значения говорят нам о том, что приложение активировано по запросу сервиса, наподобие контракта поиска или общего доступа к данным, путём ассоциации с типом файла, с помощью средства выбора файлов, посредством протокола и в других случаях. В случае с видом активации launch, другая порция данных из перечисления the Windows.ApplicationMode.- Activation.ApplicationExecutionState говорит нам о состоянии исполнения приложения до этого события. Больше об этом будет в лекции 3, а комментарии в стандартном коде выше должны пока удовлетворить ваше любопытство.

    А что такое Есть похожая функция WinJS.Binding.processAll, которая обрабатывает атрибуты data-win-bind (лекция 4) и WinJS.Resources.processAll, которая выполняет разрешение ресурсов атрибута data-win-res . Что касается args.setPromise, этот механизм касается отложенного выполнения, и мы отложим его рассмотрение до лекции 3.

    Короткий вызов app.start(); расположенный в нижней части кода, так же очень важен. Он позволяет нам быть уверенными в том, что различные события, которые поставлены в очередь при запуске приложения, будут обработаны. Мы рассмотрим это подробнее в лекции 3.

    Наконец, вы можете спросить: "Зачем нужна эта сложная конструкция Обратитесь ко второй главе книги "High performance JavaScript" (O'Reilly, 2010), Nicholas Zakas, для того, чтобы узнать, как область видимости влияет на производительность..

    Вы можете объявлять переменные в глобальном пространстве имен, конечно, и содержать их в порядке, WinJS предоставляет средства для задания ваших собственных пространств имен и классов (смотрите WinJS.Namespace.define и WinJS.Class.define), опять же, помогая минимизировать вмешательство в глобальное пространство имен.

    Познакомьтесь с Visual Studio. Если вы новичок в Visual Studio, то поначалу вы можете неуверенно чувствовать себя в этой инструментальной среде, так как она имеет множество функций, даже в Экспресс-версии. Для того, чтобы вы могли быстро ознакомиться с этой средой, я подготовил 10-минутный ролик, Video 2-1, который расположен в дополнительных данных к этой лекции для того, чтобы показать вам базовый рабочий процесс и другие основные вещи.

    Врезка: Написание кода в режиме отладки

    Из-за динамической природы JavaScript впечатляет то, что команда разработки Visual Studio нашла способ заставить IntelliSence весьма прилично работать в редакторе кода Visual Studio. (Если вы незнакомы с IntelliSence, это сервис для повышения производительности труда, который обеспечивает автозавершение кода и всплывающие подсказки по API в процессе работы. Больше вы можете узнать в материале "IntelliSence для JavaScript" (http://msdn.microsoft.com/library/bb385682.aspx)). При этом можно использовать полезный трюк, который позволяет IntelliSence работать даже лучше - это писать код, когда Visual Studio находится в режиме отладки. То есть, установить точку останова в подходящем месте вашего кода и запустить приложение в отладчике. Когда вы достигнете этой точки останова, вы можете начать писать и править код, и, так как контекст скрипта полностью загружен, IntelliSence будет работать с уже созданными экземплярами переменных, а не только с тем, что этот механизм может получить из исходного кода. Кроме того, вы можете использовать окно интерпретации (Immediate) для того, чтобы непосредственно в нём исполнять код и видеть результаты. (Однако, вам понадобится перезапустить приложение для того, чтобы получить возможность исполнять новый код).

    Быстрый старт №1: "Here My Am!" и введение в Blend для Visual Studio

    Когда моему сыну было три, он никогда - несмотря на то, что был рождён от двух инженеров-родителей и имел двух инженеров среди бабушек и дедушек - не заглядывал в углы и не появлялся в комнате со словами "Hello world!" (Привет, мир!). Нет, его особенной фразой была "Here my am!" (Вот и я!). Используя этот вариант представления себя вселенной, наше следующее приложение будет захватывать изображение с камеры, определять ваше местоположение на карте и передавать эти данные с помощью чудо-кнопки Общий доступ в Windows 8. Звучит сложно? К счастью, API WinRT делают это весьма простой задачей.

    Врезка: Сколько времени понадобится, чтобы написать это приложение?

    Написание этого приложения заняло у меня примерно три часа. "Конечно", - подумаете вы, - "вы уже написали кучу приложений, поэтому это для вас так просто!". Хорошо, и да, и нет. Во-первых, я, кроме того, писал данную часть главы в то же самое время и старался произвести код, подходящий для повторного использования. Но гораздо важнее то, что написание программы заняло у меня мало времени, так как я знал, как использовать мои инструменты, в особенности - Blend, и я знал, где я могу найти код, который уже делает большую часть из того, чего я хочу. Я имею в виду примеры из Windows SDK, которые вы можете загрузить с ресурса http://code.msdn.microsoft.com/windowsapps/.

    Как можно будет судить по множеству отличных примеров в этом учебном курсе, я надеюсь, что вы загрузите полный их набор. Перейдите по ссылке выше, найдите ссылку "Windows 8 app samples". Эта ссылка приведет вас на страницу, где вы можете получить .zip-файл, который содержит все примеры на JavaScript. Распаковав его однажды, заведите себе привычку просматривать эту папку на предмет любых API или функций, которые вам интересны. Например, код, который я использую ниже для реализации захвата данных с камеры и реализации обмена данными, взят из пары примеров. (Да, если вы откроете пример, который кажется поддерживающим только отладку на удаленном компьютере, целевая платформа, возможно, установлена в значение ARM - измените её на Any CPU для локальной отладки).

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

    Проектирование каркаса приложения

    Прежде чем мы начнём работу над кодом, сначала посмотрим на дизайнерский каркас этого приложения. О, дизайн? Да. Возможно, впервые в истории Windows, создана настоящая философия дизайна для приложений. В прошлом, с традиционными настольными приложениями, это было похоже на картину, где "что-то происходит". Конечно, были какие-то руководства по пользовательским интерфейсам, но разработчики обычно делали всё, что считали нужным, реализовывали любой опыт взаимодействия пользователя и приложения, который казался им правильным. Например, это могло выглядеть как наборы флагов в четыре уровня глубиной, спрятанные в серии модальных диалоговых окон. Естественно, подобные вещи имели смысл для определенных разработчиков; имели ли они значение для кого-нибудь еще - весьма спорный вопрос.

    Если вы когда-либо претендовали или собирались претендовать на то, чтобы быть дизайнером, сейчас - самое время передать эстафету тому, кто по-настоящему в этом разбирается, или отложить занятия программированием на год или два, и потратить это время на саморазвитие. Проще говоря, дизайн имеет значение в приложениях для Магазина Windows, и он определяет разницу между преуспевающими приложениями и приложениями, которые просто существуют в Магазине и не пользуются популярностью. И, когда у вас есть дизайн, его легче реализовать, так как вам не придётся принимать дополнительных решений о дизайне при написании кода. (Если вы всё еще хотите влезть в шкуру дизайнера и работать с приложениями вроде Adobe Illustrator, не забудьте посетить ресурс "Разработка интерфейсов пользователя для приложений" (http://msdn.microsoft.com/library/windows/apps/hh779072) для того, чтобы воспринять философию и подробности о дизайне приложений Магазина Windows, а так же - специальные ресурсы для дизайнеров).

    Когда у меня появилась идея этого приложения, я нарисовал простой каркас приложения, позволил нескольким дизайнерам посмеяться надо мной за моей спиной (и предложить улучшения) и остановился на макетах для полноэкранного режима, портретного, прикрепленного и заполняющего режимов просмотра, как показано на Рис. 2.7 и Рис. 2.8.

    Замечание. Традиционные табличные каркасы хороши для того, чтобы показать статичный вид приложения, но в "быстром и динамичном" окружении Windows 8 очень важен динамический аспект приложения - анимации и движение. Отличный дизайн приложения включает в себя не только соглашения о том, где будет расположено содержимое, но и о том, как оно будет реагировать на действия пользователя. Лекция 5 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript" обсуждает различные виды встроенных анимаций, которые можно использовать для этих целей. (рис 2.7) Полноэкранный альбомный макет и макет для заполняющего режима просмотра. Эти режимы просмотра обычно используют одинаковые макеты (с теми же полями), в которых некоторые части пропорционально уменьшены по ширине (рис 2.8) Макет для прикрепленного просмотра (слева, только для альбомного режима) и полноэкранный портретный макет (справа). Они не масштабируются

    Врезка: Проектирование для всех четырех режимов просмотра

    Так же, как я размышлял о четырех режимах просмотра для "Here my am!", я рекомендую вам сделать то же самое по одной простой причине: ваше приложение окажется в каждом из этих режимов просмотра независимо от того, приспособили вы его для этого или нет. Режимами просмотра управляют не приложения, а пользователи, поэтому, если вы не разработаете дизайн для каждого из возможных состояний, ваше приложение, вполне возможно, будет выглядеть отвратительно в этих состояниях. Вы можете, как показано в лекции 6, заблокировать ориентацию экрана в портретном или альбомном режиме, если захотите, но это оправданно в целях расширения опыта взаимодействия пользователя и приложения и никак не может служить оправданием лени разработчика. В итоге, если только у вас нет особенных причин не делать этого, каждая страница вашего приложения должна быть приспособлена к каждому из четырех режимов просмотра.

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

    Один из важных аспектов дизайна приложений для Магазина Windows заключается в понимании единообразного стиля макета: размера шрифтов заголовков, их расположения, определенные размеры границ, особенности сеточной раскладки и так далее (как отмечено на вышеприведенных рисунках). Эти рекомендации способствуют высокому уровню единообразия стиля приложений, в итоге, пользователь может интуитивно, основываясь на мышечной памяти, использовать основные элементы пользовательского интерфейса. Некоторые из этих рекомендаций можно найти в документе "Создание макета приложения" (http://msdn.microsoft.com/library/windows/apps/hh872191.aspx), их можно увидеть реализованными в шаблонах приложений вместе с другими аспектами дизайна. Это - одна из причин, по которой Microsoft обычно рекомендует начинать создание нового приложения с шаблона, начиная с него разработку. То, что я показал в вышеприведенных каркасах, отражает макет, предоставленный одним из более сложных шаблонов. В то же время, узнаваемый стиль приложений - это стартовая точка, но не жёсткое требование - приложения могут отступать от них, когда у этого есть смысл. При отсутствии же весомых причин для отступления, подтвержденных чётким дизайн-проектом, лучше от данных рекомендаций не отходить.

    Хватит говорить! Давайте просто примем к сведению, что у нас есть отличный дизайн для дальнейшей работы, наши дизайнеры потягивают капучино, удовлетворённые результатами своей работы. Теперь наша задача заключается в том, чтобы наполнить этот дизайн жизнью.

    Создаем разметку

    Для целей создания разметки, макета, настройки внешнего вида приложения, вы можете добавить в свой арсенал мощный инструмент - Blend для Visual Studio. Как вы можете знать, Blend был доступен (по более высокой цене) для дизайнеров и разработчиков, работающих с XAML (фреймворк для визуализации, которым пользуются приложения, написанные на C#, Visual Basic и C++). Теперь Blend бесплатен и поддерживает HTML, CSS и JavaScript. Я выделил последнее, так как он не только может загружать разметку и стили: он загружает и исполняет ваш код, прямо на монтажной панели (Artboard, рабочая поверхность, на которой располагаются элементы), так как этот код часто влияет на DOM, стиль элементов и так далее. И здесь присутствует Интерактивный режим (Interactive mode)… но я забегаю вперед!

    Blend и Visual Studio похожи на две стороны одной медали: они совместно используют проекты с одинаковыми форматами файлов и имеют команды для лёгкого переключения между ними, в зависимости от того, на чём вы хотите сосредоточиться - на дизайне или на разработке. Для того чтобы показать это, начнём создание приложения "Here My Am!" в Blend. Так же, как мы поступали ранее в Visual Studio, запустите Blend, выполните команду Создать проект… (New Project), выберите тип проекта - Пустое приложение (Blank App). В итоге, будет создан проект с точно такой же структурой, как ранее (Замечание: В файле Video 2-2 показаны эти шаги).

    Последуем практике написания разметки страницы в HTML - без стилей, без кода, и не обращая внимание на несколько классов, которые понадобятся нам для настроек стилей - поместим нижеприведенный код в элемент body страницы default.html, (заменяя строку <p>Content goes here</p>):

    <div id="mainContent">
    <header aria-label="Header content" role="banner">
    <h1 class="titlearea win-type-ellipsis">
    <span class="pagetitle">Here My Am!</span>
    </h1>
    </header>
    <section aria-label="Main content" role="main">
    <div id="photoSection" aria-label="Photo section">
    <h2 class="group-title" role="heading">Photo</h2>
    <img id="photo" src="images/taphere.png"
    alt="Tap to capture image from camera" role="img" />
    </div>
    <div id="locationSection" aria-label="Location section">
    <h2 class="group-title" role="heading">Location</h2>
    <iframe id="map" src="ms-appx-web:///html/map.html" aria-label="Map"></iframe>
    </div>
    </section>
    </div>

    Здесь мы видим пять элементов: главный заголовок, два подзаголовка, место для фотографии (по умолчанию - с изображением, содержащим инструкцию "коснитесь здесь" (tap here)) и элемент Если вы самостоятельно выполняете данный проект в Blend, изображение taphere.png следует добавить в проект, в папку images. Щёлкните правой кнопкой мыши по этой папке, выберите команду Добавить > Существующий элемент (Add > Existing Item) и затем, перейдя к папке images готового примера, выберите taphere.png. Файл изображения будет скопирован в ваш текущий проект.

    Вы можете видеть, что некоторым элементам назначены классы стилей. Они начинаются с Существуют две стандартных таблицы стилей - ui-dark.css (тёмная тема) и ui-light.css (светлая тема). Тёмные стили рекомендованы для приложений, которые работают с мультимедийными данными, когда тёмный фон позволяет выделить графические элементы. Мы будем использовать именно этот лист стилей, так как мы создаём программу для захвата фотографий. Светлая таблица стилей рекомендована для приложений, которые работают, в основном, с текстовым содержимым WinJS. Вы можете просмотреть их в Blend, используя закладку Правила стилей (Style Rules), показанную на Рис. 2.9. Другие стили, такие, как titlearea, pagetitle и group-title подразумевают, что вы определили их в вашем собственном листе стилей, тем самым переопределив стили WinJS для конкретных элементов.

    (рис 2.9) В Blend, закладка Правила стилей (Style Rules) позволяет вам просмотреть таблицу стилей WinJS и увидеть, что именно содержит каждый стиль. Обратите внимание на строку поиска под закладкой. Если вам нужно отыскать какой-то определенный стиль, можно не тратить время, просматривая их список. Достаточно начать вводить его имя в строке поиска и позволить компьютеру делать его работу!

    Страница, которую мы загрузим в элемент iframe, map.html, это часть нашего пакета приложения, которую мы скоро добавим, но обратите внимание на то, как мы ссылаемся на неё. Протокол ms-appx-web:/// показывает, что iframe и его содержимое будут исполняться в веб-контексте (представленном в лекции 1), тем самым, позволяя нам загружать удаленный скрипт для элемента управления карт Bing. Тройной слэш, одна из его частей, а точнее - третий слэш - это краткая запись для "пакета текущего приложения" (значение, которое вы можете получить из document.location.host), таким образом, нам не нужно создавать абсолютные URI для содержимого, которое находится в пакете.

    Для того, чтобы показать, что страницу следует загрузить в локальном контексте, протокол выглядит как ms-appx://. Важно помнить о том, что скрипты не могут разделяться между этими контекстами (включая переменные и функции), относительные пути оказываются в том же самом контексте, и взаимодействие между ними осуществляется посредством функции HTML5 postMessage, как мы увидим ниже. Это предотвращает возможность управления вашим приложением различными веб-сайтами и доступ к API WinRT.

    Кроме того, я включил в состав элементов различные атрибуты aria-* (так же, как это сделано в шаблоне), которые нужны для поддержки приложением специальных возможностей. Мы рассмотрим специальные возможности в подробностях в лекции 6 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой", но важно, чтобы с самого начала помнили о них: большинство пользователей Windows так или иначе применяют специальные возможности. И хотя некоторые из аспектов специальных возможностей несложно добавить позднее, добавление атрибута aria-* в разметку лучше выполнить раньше.

    В лекции 6 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой" мы так же увидим, как выделить строки (в том числе - метки ARIA) из нашей разметки, JavaScript и даже из манифеста и разместить их в ресурсном файле. Возможно, вы захотите сделать это ранее, поэтому посмотрите раздел "Подготовка к локализации" в этой лекции для того, чтобы узнать подробности. Однако обратите внимание на то, что в Blend разрешение ресурсов нормально не работает, поэтому вам может захотеться сначала выполнить основные настройки внешнего вида приложений, а уже потом прилагать усилия к созданию ресурсных файлов.

    Стилизация в Blend

    В данный момент, учитывая, что вы обратили должное внимание на чтение сносок, Blend отображает реальный вид приложения, который, очевидно, нуждается в стилизации, как и любой исходный каркас приложения. Посмотрите на Рис. 2.10.

    (рис 2.10) Приложение в Blend без стилизации, отображается в виде, который похож на тот, который виден в имитаторе. Если изображение taphere.png не отображается после его добавления, используйте команду меню Вид > Обновить (View > Refresh)

    Закладки около верхнего левого угла окна программы дают вам доступ к файлам вашего проекта, к Активам (Assets), таким, как элементы управления, которые вы можете добавить в ваш пользовательский интерфейс, и средство просмотра для всех правил стилей (Style Rules), определенных в текущем окружении. В левой нижней части присутствует область Динамическая DOM (Live DOM), которая позволяет вам просматривать элементы в иерархии, и закладка Устройство (Device), которая позволяет вам задавать ориентацию, разрешение экрана и состояние просмотра. Щёлкая на элементе в области Динамическая DOM (Live DOM), вы выделяет его в монтажной панели, так же, как щелчок по элементу в монтажной панели, выделяет его в области Динамическая DOM (Live DOM).

    В правой части вы видите то, с чем близко подружитесь: области Атрибуты HTML (HTML Attributes) и Свойства CSS (CSS Properties). Последняя отображает в верхней своей части все источники стилей, которые были применены к выделенному элементу и точное расположение этих стилей (вечная головная боль при работе с CSS). То, что выбрано в данной области. помните, определяет, куда будут записаны изменения, внесенные в панель свойств ниже, поэтому очень внимательно следите за тем, что именно вы выделяете.

    Теперь, чтобы привести нашу исходную страницу к виду, напоминающему каркас приложения, нам нужно поработать с элементами и создать необходимые селекторы и стили. Для начала, я рекомендую создать сетку из одной ячейки (1х1) в теле (body) страницы, так как это улучшит отображение контента на монтажной панели Blend. Поэтому, добавьте display: -grid; -ms-grid-rows: 1fr; -ms-grid-columns: 1fr; в default.css для данного элемента.

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

  • Установите позицию вставки правила стиля в виде жёлто-оранжевой линии на закладке Правила стилей (Style Rules) в Blend. Это точно определяет, где именно будет создано новое правило.
  • Щёлкните правой кнопкой мыши по элементу, который вы хотите стилизовать в панели Динамическая (Live DOM) и выберите команду Создать правило стиля на основе ID элемента (Create Style Rule From Element Id) или команду Создать правило стиля на основе класса элемента (Create Style Rule From Element Class). Примечание. Если оба эти варианта не активны, перейдите на панель Атрибуты HTML (HTML Attributes) (в верхней правой части окна) и добавьте ID, класс, или и то и другое. В противном случае вам придётся вручную править таблицы стилей для управления стилями (особенно в случае с встроенными стилями), так что это избавит вас от сложностей в будущем. Данные действия приведут к созданию нового правила стиля в таблице стилей приложения (в default.css). В панели свойств CSS, в правой части экрана, найдите правило, которое было создано и добавьте необходимые свойства стиля в панель, которая расположена ниже.
  • Повторите эти действия для остальных элементов.
  • Так, для элемента div mainContent мы создаем правило из Id и настраиваем его, задавая display: -ms-grid;-ms-grid-columns: 1fr; и -ms-grid-rows: 128px 1fr 60px;. (Рис. 2.11) Эти действия позволят нам создать базовые вертикальные области каркаса приложения. Обычно, вам не захочется устанавливать правые или левые поля прямо в данной сетке, так как нижняя часть часто имеет горизонтально прокручиваемое содержимое, которое выступает за левый и правый края. В нашем случае, мы можем использовать одну сетку, но вместо этого мы добавим эти поля во вложенной сетке внутри элементов заголовка и раздела.

    (рис 2.11) Установка свойств сетки для элемента div mainContent. Обратите внимание на то, как флаг Просматривать только заданные свойства (View Set Properties Only) (в верхней правой части) упрощает просмотр того, какие стили устанавливаются для текущего правила. Кроме того, обратите внимание, как на монтажной панели (Artboard) отмечены столбы и строки сетки, в том числе - с помощь слайдеров (обведены) для управления строками и столбцами непосредственно на монтажной панели.

    Показ работы над стилями, настройки различных уровней разметки и подходящих стилей для медиазапросов, соответствующих различным состояниям просмотра, лучше всего выглядит на видео. В частности, в файле Video 2-2 (оно находится среди дополнительных данных к курсу) вы можете увидеть этот процесс, начиная с создания проекта, настройки стилей для различных состояний просмотра, до переход в Visual Studio (для этого нужно щёлкнуть правой кнопкой проект в Blend и выбрать команду Изменить в Visual Studio (Edit In Visual Studio)) и запуска приложения в имитаторе для того, чтобы убедиться в том, что всё настроено верно. Кроме того, в видео вы можете оценить объем времени, который нужен для работы со стилями, если вам хорошо знакомы инструменты разработки.

    В результате всех этих действий вид программа в имитаторе соответствует ранее разработанному каркасу, смотрите рисунки 2.12., 2.13., 2.14. - и все настройки стилей полностью включены в соответствующие медиа-запросы файла default.css. Гораздо важнее то, что Blend отображает нам результаты работы в реальном времени, тем самым сохраняя огромное количество времени в сравнении с тем, если бы нам нужно было, после правок, внесенных в CSS, каждый раз запускать приложение - уверен, вы знакомы с этим неприятным процессом! (И экономия времени даже больше с Интерактивным режимом; обратитесь к видеофайлу Video 4-1, который находится среди дополнительных материалов к лекции 4, "Элементы управления, их стилизация и привязка данных").

    (рис 2.12) Полноэкранный альбомный режим просмотра (рис 2.13) Заполняющий режим просмотра (только для альбомного режима) (рис 2.14) Режим прикрепленного просмотра (только для альбомного режима) и полноэкранный портретный режим; они показаны в пропорциональном масштабе

    Добавление кода

    Завершим реализацию приложения в Visual Studio. Щёлкните правой кнопкой по имени проекта на панели Проекты (Projects) в Blender и выберите команду Изменить в Visual Studio (Edit In Visual Studio), если вы этого еще не сделали. Обратите внимание на то, что если ваш проект уже загружен в Visual Studio, когда вы переходите в эту среду, вы (по умолчанию) увидите предложение перезагрузить измененные файлы. Ответьте утвердительноС другой стороны, обратите внимание на то, что Blend не сохраняет файлы автоматически при входе в Интерактивный режим (Interactive Mode) и выходе из него. Если вы сделали изменения в тех же самых файлах, открытых в Visual Studio, перешли в Blend и перезагрузили файлы, вы можете потерять изменения. В данный момент у нас есть макет приложения и стили для всех необходимых режимов просмотра, и мы можем не беспокоиться о коде, за исключением внесения в него небольших улучшений, о которых мы скоро поговорим.

    Что это означает, так то, что, по большей части, мы можем просто написать код нашего приложения для разметки, но не для разметки со стилизацией, что, конечно, является наилучшим подходом при работе с HTML/CSS. Вот возможности, которые мы сейчас реализуем:

  • Элемент управления карт Bing в разделе Местоположение (Locations) показывает пользователю его текущее расположение. Мы просто показываем эту карту автоматически, здесь нет элемента управления, который запускает этот процесс.
  • Используя API WinRT для работы с камерой, мы получаем фотографию в ответа на прикосновение к элементу img Photo.
  • Передаем фотографию и данные о местоположении чудо-кнопке Общий доступ, когда пользователь активирует её.
  • На Рис. 2.15 показано, на что будет похоже приложение, когда мы завершим работу.

    (рис 2.15) Готовое приложение "Here my am!" (хотя здесь я уменьшил масштаб карты, чтобы вы не могли точно назвать место, где я живу!)

    Создание карты с информацией о текущем местоположении

    Для отображения карты мы используем веб-элемент управления карт Bing, экземпляр которого создан на странице map.html, которая загружена в элемент iframe главной страницы. Страница загружает скрипт элемента управления карт Bing из удалённого источника и исполняется в веб-контексте. Обратите внимание на то, что мы, кроме того, можем воспользоваться SDK для карт Bing (лекции 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    Таким образом, разместим файл map.html в папке html. Для этого щёлкните правой кнопкой мыши по проекту, выберите команду Добавить > Создать папку (Add > New Folder), введите для неё имя html. Затем щёлкните правой кнопкой по этой папке, выберите команду Добавить > Создать элемент (Add > New Item) и выберите HTML-страницу (HTML Page). Когда новая страница отобразится на экране, замените её содержимое на следующееОбратите внимание на то, что вы должны заменить значение параметра credentials в функции init на собственный ключ, полученный на https://www.bingmapsportal.com/ :

    <!DOCTYPE html>
    <html>
    <head>
    <title>Map</title>
    <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0"></script>
    
    <script type="text/javascript">
    //Глобальные переменные
    var map = null;
    
    document.addEventListener("DOMContentLoaded", init);
    window.addEventListener("message", processMessage);
    
    //Функция для преобразования строки к синтаксису { functionName: ..., args: [...] }
    //в вызове именованной функции с такими аргументами. Основана на стандартном
    //диспетчере, который позволяет коду в iframe быть вызванным посредством
    //postMessage. 
    function processMessage(msg) {
    //Проверяет данные и источник (в данном случае - страницу, работающую в локальном
    //контексте)
    if (!msg.data || msg.origin !== "ms-appx://" + document.location.host) {
    return;
    }
    
    var call = JSON.parse(msg.data);
    
    if (!call.functionName) {
    throw "Message does not contain a valid function name.";
    }
    
    var target = this[call.functionName];
    
    if (typeof target != 'function') {	
    throw "The function name does not resolve to an actual function";
    }	
    	
    return target.apply(this, call.args);	
    }	
    
    
    function notifyParent(event, args) {	
    //Добавляет имя события к аргументам обекта и преобразует в строку в
    //качестве сообщения.
    args["event"] = event;	
    window.parent.postMessage(JSON.stringify(args),	
    "ms-appx://" + document.location.host);	
    }	
    
    
    
    //Создает карту (хотя пространство имен не может быть определено без возможности связи)
    function init() {	
    if (typeof Microsoft == "undefined") {	
    return;	
    }	
    
    map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {
    //Замените эти учетные данные на свои, полученные на 
    //http://msdn.microsoft.com/en-us/library/ff428642.aspx 
    credentials: "...",
    //zoom: 12,
    mapTypeId: Microsoft.Maps.MapTypeId.road
    });
    }
    
    function pinLocation(lat, long) {
    if (map === null) {
    throw "No map has been created";
    }
    
    var location = new Microsoft.Maps.Location(lat, long);
    var pushpin = new Microsoft.Maps.Pushpin(location, { draggable: true });
    
    Microsoft.Maps.Events.addHandler(pushpin, "dragend", function (e) {	
    var location = e.entity.getLocation();	
    notifyParent("locationChanged",	
    { latitude: location.latitude, longitude: location.longitude });
    });	
    
    map.entities.push(pushpin);	
    map.setView({ center: location, zoom: 12, });
    return;	
    }	
    
    function setZoom(zoom) {	
    if (map === null) {	
    throw "No map has been created";
    }	
    
    map.setView({ zoom: zoom });
    }
    </script>
    </head>
    <body>
    <div id="mapDiv"></div>
    </body>
    </html>

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

    В верхней части страницы вы можете видеть ссылку на удалённый скрипт элемента управления карт Bing. Мы можем здесь ссылаться на удалённые скрипты, так как страница загружается в веб-контексте внутри элемента iframe (ms-appx-web:// в default.html). Затем вы можете видеть, как функция init вызывается DOMContentLoader и создаёт элемент управления карты. Далее, у нас есть еще пара методов, pinLocation и setZoom, которые, если понадобятся, могут быть вызваны из основного приложения.

    Конечно, так как эта страница загружена в iframe в веб-контексте, мы не можем просто вызвать эти функции напрямую из кода нашего приложения. Вместо этого мы используем функцию HTML5 postMessage, которая вызывает событие message в iframe. Это важный момент: локальный и веб-контексты разделены, поэтому произвольный веб-контент не может управлять приложением или получать доступ к API WinRT. Эти два контекста разделены границей между приложением и веб'ом, которую может пересечь лишь postMessage.

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

    Для того, чтобы посмотреть на то, как это работает, взглянем на то, как мы вызываем pinLocation из default.js. Для того, чтобы выполнить этот вызов, нам нужны некоторые координаты, которые мы можем получить из API для определения местоположения (Geolocation) WinRT. Мы делаем это в обработчике события onactivated, поэтому местоположение пользователя задаётся при старте приложения (и сохраняется в переменной lastPosition позже для организации общего доступа):

    //Поместите это после строки: var activation = Windows.ApplicationModel.Activation;
    var lastPosition = null;
    
    
    //Поместите это после args.setPromise(WinJS.UI.processAll());
    var gl = new Windows.Devices.Geolocation.Geolocator();
    
    gl.getGeopositionAsync().done(function (position) {	
    //Сохраним для общего доступа	
    lastPosition = { latitude: position.coordinate.latitude,
    longitude: position.coordinate.longitude };	
    
    callFrameScript(document.frames["map"], "pinLocation", [position.coordinate.latitude, position.coordinate.longitude]);
    });

    Здесь callFrameScript - это просто небольшая вспомогательная функция, которая превращает целевой элемент, имя функции и аргументы в соответствующий вызов posMessage:

    //Поместите это перед app.start();	
    function callFrameScript(frame, targetFunction, args) {	
    var message = { functionName: targetFunction, args: args };	
    frame.postMessage(JSON.stringify(message), "ms-appx-web://" + document.location.host);
    	}

    Некоторые замечания по этому коду. Для того чтобы получить координаты, вы можете использовать API WinRT для определения местоположения или API HTML5 для определения местоположения. Они почти одинаковые, с небольшими различиями, описанными в лекции 3 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript", "Ввод данных и сенсоры", во врезке: "Определение местоположения в HTML5". Это API присутствует в WinRT, так как другие поддерживаемые языки (C# и C++) не имеют доступ к API определения местоположения HTML5. Мы, в этом курсе, сосредоточены на API WinRT, поэтому мы просто используем функции в пространстве имен Windows.Devices.Geolocation.

    Далее, в качестве второго параметра postMessage, вы можете видеть комбинацию из ms-appx[-web]:// и document.location.host. Это означает: "текущее приложение из локального [или веб] контекста", которое является подходящим источником сообщения. Обратите внимание на то, что мы используем то же самое значение для того, чтобы проверить источник сообщения при его получении: код в map.html проверяет, пришло ли сообщение из локального контекста приложения, тогда как код в default.js проверяет, что сообщение пришло из веб-контекста приложения. всегда будьте уверены в том, что соответствующим образом проверяете источники сообщения; посмотрите материал "Разработка безопасных приложений" (http://msdn.microsoft.com/library/windows/apps/hh849625.aspx).

    Наконец, вызов getGeoPositionAsync содержит интересную конструкцию, где мы делаем вызов и используем внутри него цепочку из функции done, аргумент которой - еще одна функция. Это - весьма распространённый подход, который мы можем видеть, работая с API WinRT, для любого API, которому может потребоваться более 50 мс для завершения асинхронной операции. Подобное решение было принято так, что использование API ведет к созданию быстрых и динамичных приложений по умолчанию.

    В JavaScript подобные API возвращают то, что называется promise-объектом, он представляет результаты, которые будут получены когда-нибудь в будущем. Каждый такой объект имеет метод done, первый аргумент которого - функция, которая будет вызвана по завершении операции, обработчик завершения (completed handler). В учебном курсе мы еще коснёмся данной темы, в частности, поговорим о функции then, которая похожа на done, но поддерживает дальнейшее объединение функций в цепочку (лекция 3) и о том, как promise-объекты в более общем виде используются в асинхронных операциях (лекция 5 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой").

    Аргумент, который передается обработчику завершения содержит результат асинхронного вызова, в нашем случае это объект Маркер местоположения можно перемещать, однако сейчас это не окажет никакого влияния на наше приложение. Смотрите раздел "Исключительное доверие: Принимаем сообщения из iframe" ниже для того, чтобы узнать, как мы можем получить сведения об изменении местоположения с карты.

    Еще одно, последнее, примечание по асинхронным API. Внутри API WinRT все асинхронные функции имеют "Async" в своих именах. Так как подобная практика не принята в среде JavaScript или DOM API, асинхронные функции внутри WinJS не используют данный суффикс. Другими словами, WinRT создана нейтральной по отношению к языкам программирования, а WinJS разработана с учетом языковых соглашений, характерных для JavaScript.

    О, подождите, манифест!

    Сейчас вы уже могли испытать тот код, который приведен выше, и столкнуться с исключением "Доступ запрещен" при попытке вызова getGeoPositionAsync. Почему это так? Исключение говорит о том, что мы не указали возможность Расположение (Location) в манифесте. Без включения этой возможности, вызов вроде этого, зависящий от возможности, вернет исключение.

    Если вы запускаете пример в отладчике, это исключение покажет диалоговое окно. Если вы запускаете его вне отладчика - с плитки на Начальном экране - вы увидите, что приложение просто прекратило работать, не показав ничего, кроме экрана-заставки. Это - обычное поведение для необработанных исключений. Для того, чтобы предотвратить подобное поведение, добавим функцию для обработки ошибок в качестве второго параметра метода done асинхронного promise-объекта:

    gl.getGeopositionAsync().done(function (position) {
    //...	
    }, function(error) {	
    console.log("Unable to get location.");	
    });

    Функция console.log записывает строку в окно Консоли JavaScript (JavaScript Console) в Visual Studio, а это, очевидно, хорошая идея. Сейчас запустите приложение вне отладчика, и вы увидите, что оно запустилось, так как исключение теперь признано "обработанным". В отладчике установите точку останова на строку console.log и точка останова сработает после того, как появится исключение и вы нажмете Далее (Continue). (Пока это всё, что мы делаем с появляющимися ошибками; в лекции 1 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript" мы добавим более подходящее сообщение и команду повтора действия).

    Если диалоговое окно исключения вам надоело, вы можете управлять тем, информацию о каких исключениях показывать во всплывающих окнах с помощью диалогового окна Отладка > Исключения (Debug > Exceptions), показанного на Рис. 2.16, в разделе Исключения JavaScript времени выполнения (JavaScript Runtime Exceptions). Если вы снимете флажки в колонке Необработанное пользовательским кодом (User-unhandled), вы не увидите диалоговое окно, когда происходит то или иное исключение.

    (рис 2.16) Исключения JavaScript времени выполнения в диалоговом окне Отладка > Исключения (Debug > Exceptions) в Visual Studio

    Вернемся к возможностям: для того, чтобы это приложение правильно себя вело, откройте package.appmanifest вашего проекта, выберите закладку Возможности (Capabilities) и включите Расположение (Location), как показано на Рис. 2.17.

    (рис 2.17) Установка возможности Расположение (Location) в редакторе манифеста Visual Studio. (Обратите внимание на то, что Blend поддерживает правку манифеста лишь в качестве XML-файла)

    Теперь, даже если мы объявили возможность, геолокация всё еще требует разрешения пользователя, как было указано в лекции 1. При первом запуске приложения с установленной возможность вы увидите всплывающее окно, похожее на то, что изображено на Рис. 2.18. Если пользователь запретит доступ в этом окне, обработчик ошибки снова будет запущен, так как API снова выдаст исключение запрета доступа.

    (рис 2.18) Типичное окно, позволяющее узнать мнение пользователя, отражающее пользовательскую цветовую схему, которое появляется при первой попытке приложения вызвать API, доступ к которому осуществляется через брокера (в данном случае - геолокационное API). Если пользователь запретит доступ, API выдаст ошибку, но позже пользователь может изменить решение в панели Параметры > Разрешения (Settings > Permissions).

    Врезка: как сбросить информацию о решении пользователя для целей тестирования?

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

    Обратите внимание на то, что когда пользователь изменяет настройки разрешений, приложение никак не оповещается об этом. Приложение может обнаружить это изменение, лишь попытавшись использовать API снова. Мы вернемся к этому в лекции 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    Получение фотографии с камеры

    Хоть это и необычно, я надеюсь, что идея добавить описание получений фотографий с камеры в раздел "быстрый старт", заставит вас сомневаться во вменяемости автора. Не потребуется ли для этого огромного количества кода? Да, так было, но в Windows 8 это не так. Все сложные особенности захвата данных с камеры отлично инкапсулированы внутри API Windows.Media.Capture, так что, в итоге, мы можем добавить в приложение эту возможность с помощью нескольких строк кода. Это хороший пример того, как небольшой динамичный код, наподобие JavaScript комбинируется с отлично спроектированными компонентами WinRT - и то и другое в системе, и тем и другим вы можете пользоваться - создавая мощный союз.

    Для того, чтобы реализовать эту возможность, сначала нам нужно вспомнить, что камера, как и GPS-приёмник, относится к устройствам, от которых может пострадать приватность пользователя, поэтому возможность, связанную с ней, так же нужно объявлять в манифесте, Рис. 2.19.

    (рис 2.19) Возможность, связанная с камерой в редакторе манифеста Visual Studio

    При первом использовании камеры во время выполнения приложения, вы увидите еще одно диалоговое окно, запрашивающее разрешение пользователя, Рис. 2.20.

    (рис 2.20) Всплывающее окно для получения разрешения пользователя на применение камеры. Вы можете в любой момент изменить эту настройку в панели Параметры > Разрешения (Settings > Permissions)

    Теперь нам нужно настроить элемент img для того, чтобы он мог реагировать на жест прикосновения. Для этого нам нужно просто добавить прослушиватель события click, который срабатывает для любых способов ввода (сенсорный интерфейс, мышь, перо), как мы увидим в лекции 3 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".

    var image = document.getElementById("photo");
    image.addEventListener("click", capturePhoto.bind(image));

    Здесь мы указываем capturePhoto в качестве обработчика события и используем функциональность объектного метода bind для того, чтобы объект this внутри capturePhoto был напрямую связан с элементом img. В результате, этот обработчик может быть использован для любого количества элементов, так как он не ссылается на DOM.

    //Расположите это под var lastPosition = null;
    var lastCapture = null;
    
    
    //Расположите это после callFrameScript	
    function capturePhoto() {	
    //В соответствии с вызовом .bind() в addEventListener, "this" будет элементом image,
    //но нам нужна копия для асинхронно завершившегося обработчика ниже.	
    var that = this;	
    
    var captureUI = new Windows.Media.Capture.CameraCaptureUI();
    
    //Показывает, что мы хотим получить PNG-изображение не больше, чем целевой элемент -	
    //пользовательский интерфейс автоматически обрежет изображение под этот размер	
    captureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png;
    captureUI.photoSettings.croppedSizeInPixels =	
    { width: this.clientWidth, height: this.clientHeight };	
    
    captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo)
    .done(function (capturedFile) {
    //Убедитесь, что проверили, подходит ли вам возвращенный элемент: он может содержать null, если
    //пользователь отменил действие.
    if (capturedFile) {
    lastCapture = capturedFile; //Сохраняем для целей Общего доступа (Share)
    that.src = URL.createObjectURL(capturedFile, {oneTimeOnly: true});
    }
    }, function (error) {
    console.log("Unable to invoke capture UI.");
    });
    }

    Нам необходимо создать локальную копию this внутри обработчика click, так как, как только мы оказываемся внутри функции завершения асинхронного запроса (посмотрите функцию внутри captureFileAsync.done) мы оказываемся в новой области видимости и объект this изменяется. Принято такую копию this называть that. Берем это?

    Для того чтобы запустить интерфейс камеры, нам лишь нужно создать экземпляр Windows.Media.Capture.CameraCaptureUI с ключевым словом new (обычный способ создания экземпляров динамических объектов WinRT), настроить его на желаемый формат и размер изображения (это одни из многих других возможных параметров, которые обсуждаются в лекции 4 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript") и вызвать captureFileAsync. Здесь будет произведена проверка манифеста, и, если необходимо, будет запрошено разрешение пользователя.

    Это асинхронный вызов, поэтому мы используем .done в конце с обработчиком завершения, который в данном случае принимает объект Параметр {oneTimeOnly: true} показывает, что URI не подлежит повторному использованию и должен быть аннулирован с помощью URL.revokeObjectURL, когда он больше не используется, как в случае, когда мы заменяем img.src на новое изображение. Без использования данного подхода мы столкнёмся с утечкой памяти при отображении каждого нового изображения. Если ранее вы использовали URL.createObjectURL, вы увидите, что второй параметр теперь представляет собой неупорядоченный набор свойств (property bag), что объединяет его с наиболее свежими спецификациями W3C!

    Обратите внимание на то, что captureFileAsync вызовет обработчик завершения, если пользовательский интерфейс был успешно отображен, но пользователь нажал кнопку Назад и фото не было сделано. Именно поэтому присутствует дополнительная проверка правильности captureFile. Обработчик ошибки в promise-объекте, в свою очередь, сначала перехватит ошибки запуска пользовательского интерфейса, но обратите внимание на то, что при отсутствии разрешения пользователя на работу с камерой, сообщение об этом появится непосредственно в пользовательском интерфейсе камеры (Рис. 2.21), поэтому нет необходимости иметь обработчик ошибки для этих целей в данном API. В большинстве случаев, однако, вам понадобится соответствующий обработчик ошибок для асинхронных вызовов.

    (рис 2.21) Сообщение в пользовательском интерфейсе камеры, когда пользователь не разрешил доступ к ней (слева); вы можете изменить разрешения посредством панели Разрешения чудо-кнопки Параметры (Settings) (справа)

    Делимся удовольствием!

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

    Windows 8 вместо этого предложила понятие контракта Общий доступ (Share), который используется для применения возможностей чудо-кнопки Общий доступ (Share) во всех приложениях, реализующих данный контракт. Когда вы, находясь в приложении, нажимаете на чудо-кнопку Общий доступ, Windows запрашивает у приложения исходные (source) данные. Затем система проверяет данные и генерирует список целевых (target) приложений, которые способны воспринимать данные в этом формате (в соответствии с манифестом), и отображает список приложений в панели чудо-кнопки Общий доступ. Когда пользователь выбирает целевой приложение, это приложение активируется и ему передаются исходные данные. Коротко говоря, контракт - это промежуточная абстракция, находящаяся между двумя приложениями, таким образом, приложение-источник и приложение-приемник никогда не нуждаются в информации друг о друге.

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

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

    Этот запрос приходит через событие Так как мы, когда приложение выполняется, постоянно прослушиваем событие datarequested и добавляем прослушиватель события лишь один раз, нам не нужно беспокоиться о том, чтобы удалять его, вызывая removeEventListener. Подробности смотрите в разделе "События WinRT и removeEventListener" в лекции 3. Для начала, нам лишь нужно установить соответствующий прослушиватель события, разместив нижеприведенный код в событии activated в файле default.js после установки прослушивателя для события click элемента img:

    var dataTransferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.getForCurrentView();
    dataTransferManager.addEventListener("datarequested", provideData);

    Идея текущего представления (current view) заключается в том, что это то, что мы видим в появляющихся время от времени областях. Это отражает то, что приложение может быть запущено по разным причинам - таким, как обслуживание контракта - и, таким образом, предоставлять пользователю различные страницы или представления. Эти представления (не связанные с режимами просмотра, такими, как прикрепленный, заполняющий и другие) могут быть активны одновременно. Для обработки этих состояний убедитесь в том, что ваш код реагирует на них, определенные API возвращают объекты, соответствующие текущему представлению приложения, как мы видим здесь.

    В данном событии обработчик принимает объект Windows.ApplicationModel.DataTransfer.DataRequest в параметрах события (e.request), которые хранятся в объекте DataPackage (e.request.data). Для того чтобы сделать данные доступными для целей общего доступа, вы заполняете пакет данных (data package) информацией в доступном вам формате. (Мы сохраняем данные в lastPosition и lastCapture.) В нашем случае, мы убеждаемся в том, что имеем фотографию и информацию о местоположении и заполняем свойства текста и изображения (если вы хотите получить карту от сервиса Bing для передачи её в другое приложение, посмотрите материал "Получение статической карты" (http://msdn.microsoft.com/library/ff701724.aspx):

    //Поместите это после capturePhoto 
    function provideData(e) {
    var request = e.request;
    var data = request.data;
    
    if (!lastPosition || !lastCapture) {
    //Нечего передавать, поэтому выходим
     return;
    }
    
    data.properties.title = "Here My Am!";
    
    data.properties.description = "At ("	
    + lastPosition.latitude + ", " + lastPosition.longitude + ")";	
    	
    //Передавая изображение, добавляем миниатюру	
    var streamReference =	
    Windows.Storage.Streams.RandomAccessStreamReference.createFromFile(lastCapture);
    data.properties.thumbnail = streamReference;	
    // Рекомендовано использовать и setBitmap и setStorageItems при передаче отдельного изображения
    //так как целевое приложение может поддерживать лишь что-то одно.
    
    //Поместим файл изображения в массив и передадим его setStorageItems data.setStorageItems([lastCapture]);
    
    //Методу setBitmap требуется RandomAccessStream. data.setBitmap(streamReference);
    }

    Последняя часть этого кода представляет собой стандартную реализацию возможности по передаче изображения из файла (которое находится в lastCapture). Я взял большую часть этого кода из примера "Приложение-источник для общего доступа", (лекции 1 курса "Программная логика приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript и их взаимодействие с системой".

    С этим последним дополнением, и с подходящим приложением-приемником (таким, как в примере "Приложение-цель для общего доступа", (http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782), как показано на Рис. 2.22), сейчас мы получили весьма функциональное приложение, которое состоит из 35 строк HTML-кода, 125 строк CSS и 100 JavaScript-строк!

    (рис 2.22) Передача данных (обезьяна увидела, обезьяна сделала!) в приложение из примера реализации целевого приложения Windows SDK. Целевое приложение частично перекрывает текущее приложение, таким образом, пользователь никогда не потеряет контекст приложения

    Исключительное доверие: Принимаем сообщения из iframe

    Вот еще один фрагмент кода, который я включил в программу "Here My Am!" для того, чтобы завершить пример базового взаимодействия между приложением и iframe: возможность отправлять сообщения из iframe назад, в приложение. В нашем случае, мы хотим знать, когда изменилось положение маркера местоположения для того, чтобы обновить lastPosition.

    Для начала, вот простая стандартная функция, которую я добавил в map.html для того, чтобы включить в неё подходящий вызов postMessage, направленный к приложению, из iframe:

    function function notifyParent(event, args) {
    Добавляем имя события к объекту, содержащему аргументы, и конвертируем в строку для формирования сообщения
    args["event"] = event;	
    window.parent.postMessage(JSON.stringify(args), "ms-appx://" + document.location.host);

    Эта функция берет имя события, добавляет его к объекту, содержащему параметры, конвертирует всё это в строку и отправляет результат туда, откуда её вызвали.

    Когда маркер перетащили, карта Bing генерирует событие dragend, к которому мы прикрепим обработчик и обработаем событие в функции setLocator сразу после того, как маркер был создан (так же в map.html):

    var pushpin = new Microsoft.Maps.Pushpin(location, { draggable: true });
    
    Microsoft.Maps.Events.addHandler(pushpin, "dragend", function (e) {	
    var location = e.entity.getLocation();	
    notifyParent("locationChanged",	
    { latitude: location.latitude, longitude: location.longitude });
    });

    Вернемся назад, в default.js (то есть - в приложение) и добавим прослушиватель для входящих messages (сообщений) внутрь app.onactivated:

    window.addEventListener("message", processFrameEvent);

    Обработчик processFrameEvent ищет в сообщении информацию о событии и поступает соответствующим образом:

    function processFrameEvent (message) {	
    //Проверяем данные и источник (в нашем случае это - страница из веб-контекста)	
    if (!message.data || message.origin !== "ms-appx-web://" + document.location.host) {
    return;	
    }	
    
    if (!message.data) {
    return;
    }
    
    var eventObj = JSON.parse(message.data);
    
    switch (eventObj.event) {	
    case "locationChanged":	
    lastPosition = { latitude: eventObj.latitude, longitude: eventObj.longitude };
    break;	
    
    default:
    break;
    }
    };

    Ясно, что здесь больше кода, чем нам нужно для того, чтобы обработать одно сообщение или событие из iframe, но я хочу предоставить вам универсальное решение, которое вы сможете использовать в своих приложениях и в других случаях.

    Другие шаблоны

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

    Приложение с фиксированным макетом (Fixed Layout Template)

    "Проект приложения для Магазина Windows, которое масштабируется с использованием макета с фиксированными пропорциями" (Описание из Blend/Visual Studio).

    Недавно мы видели приложение, которое подстраивается под изменения отображаемой области, изменяя свой макет. В "Here My Am!" мы использовали CSS-сетку с автоматически настраиваемыми областями (значения 1fr в строках и столбцах). Такой подход хорошо работает для приложений с содержимым, которое хорошо поддаётся масштабированию и для приложений, которые могут показывать дополнительный контент, такой, как заголовки новостей или результаты поиска, когда у них больше места.

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

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

    <body>	
    <div data-win-control="WinJS.UI.ViewBox">
    <div class="fixedlayout">	
    <p>Content goes here</p>	
    </div>	
    </div>	
    </body>

    В файле default.css вы можете видеть элемент body, которому задан стиль "резинового" блока CSS, центрированного на экране, и элемент fixedLayout, установленный на размер 1024х768 (минимальный размер окон полноэкранных альбомных приложений и приложений в режиме заполняющего просмотра). Размещая содержимое внутри дочернего элемента div, который принадлежит элементу ViewBox, вы можете быть уверены в том, что работаете с этими фиксированными размерностями. ViewBox автоматически настроит масштаб того, что находится внутри, и, при необходимости, добавит пустые пространства сверху и снизу или справа и слева для сохранения пропорций.

    Обратите внимание на то, что подобные приложения могут не поддерживать интерактивный прикрепленный режим. В игры, например, невозможно играть при уменьшении размеров их окна. В подобном случае приложение может просто поставить игру на паузу и попытаться выйти из прикрепленного режима, если пользователь пытается продолжить игру. Мы вернемся к этому в лекции 6.

    Приложение навигации (Navigation Template)

    "Проект приложения для Магазина Windows, которое содержит предопределенные элементы управления для навигации" (Описание из Blend/Visual Studio).

    Шаблон Приложение навигации построен на базе шаблона Пустое приложение путём добавления к нему системы навигации по страницам. Как было сказано в лекции 1, приложения для Магазина Windows, написанные на JavaScript, лучше реализовать в виде единственной HTML-страницы, выступающей в роли контейнера, в который динамически загружаются другие страницы. Это позволяет организовать плавные переходы (так же, как и анимации) между этими страницами и сохранить скриптовый контекст.

    Этот шаблон, и другие оставшиеся, использует элемент управления Page Navigator, который облегчает загрузку (и отправку) страниц таким способом. Вам нужно лишь создать сравнительно простую структуру для описания каждой страницы и её поведения. Мы рассмотрим это в лекции 3.

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

    Приложение таблицы (Grid Template)

    "Трехстраничный проект приложения для Магазина Windows, которое осуществляет переходы между группами элементов, расположенных в сетке. Сведения о группах и элементах отображаются на выделенных страницах" (Описание из Blend/Visual Studio).

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

    В дополнение к навигации, шаблон Приложение таблицы показывает пример управления коллекциями данных посредством класса WinJS.Binding.List. Эту тему мы подробно рассмотрим в лекции 5, "Коллекции и элементы управления для коллекций". Кроме того, он предоставляет структуру для создания панели приложения и показывает, как упростить поведение приложения в прикрепленном режиме.

    Имя шаблона, кстати, получилось от особого табличного (сеточного) макета, который используется для отображения коллекций данных, а не от CSS-сетки (CSS grid).

    Приложение с разделением (Split Template)

    "Двухстраничный проект приложения для Магазина Windows, которое осуществляет переходы между группированными элементами. Первая страница позволяет выбрать группу, а вторая отображает список элементов вместе со сведениями о выбранном элементе" (Описание из Blend/Visual Studio).

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

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

    Что мы только что изучили:

  • Как создать новое приложение для Магазина Windows с использованием шаблона Пустое приложение.
  • Как запустить приложение внутри локального отладчика и внутри имитатора, о роли отладки на удалённой машине.
  • Функции имитатора, которые включают возможность симулировать касания, устанавливать состояния просмотра, менять разрешение и плотность пикселей.
  • Основные структуры проекта приложения для Магазина Windows, в том числе - ссылки на WinJS.
  • Основную структуру активации приложения посредством события WinJS.Application.onactivated
  • Роль и полезность проектирования каркаса приложения при разработке приложения, включая важность проектирования интерфейсов для всех состояний просмотра, где особую важность приобретает видимость элементов и макет.
  • Мощь Blend для Visual Studio для быстрой и эффективной стилизации разметки приложения. Blend, кроме того, является отличным инструментом для отладки CSS.
  • Как безопасно использовать веб-контент (такой, как карты Bing) внутри веб-контекста iframe и как организовать обмен данными между подобной страницей и локальным контекстом приложения, используя метод postMessage.
  • Как использовать API WinRT, в особенности асинхронные методы, использующие promise-объекты, как пользоваться определением местоположения и захватом изображений с камеры. Асинхронные операции возвращают promise-объекты, которым вы предоставляете обработчик завершения (и, необязательно, обработчики ошибок и этапов выполнения задания), для методов promise-объектов then или done.
  • Возможности, заявленные в манифесте, определяют, может ли приложение использовать конкретные API WinRT. Исключения возникают, если приложение пытается воспользоваться API, не объявляя соответствующую возможность.
  • Как передавать данные в другие приложения, используя контракт Share (Общий доступ) в ответ на событие datarequested.
  • Виды приложений, поддерживаемые другими шаблонами приложений: Приложение с фиксированным макетом, Приложение навигации, Приложение таблицы и Приложение с разделением.
  • Вернуться к учебному плану