Содержание статьи
Windows 10 стала единственной программной платформой Microsoft, управляющей различными устройствами: от микроконтроллеров и до больших серверных систем. Только вдумайся: одно ядро для ПК, для миниатюрных девайсов (Internet of Things), консоли (Xbox One), моноблока (Surface Hub), устройств дополненной реальности HoloLens! Между ядром и прикладными программами расположена система выполнения UWP. Она служит подсистемой, которая предоставляет приложениям аппаратную функциональность, управляемую ядром посредством драйверов устройств. Программистам, соответственно, предложены высокоуровневые средства для взаимодействия с системой. В этой статье мы в деталях разберемся в платформе UWP и в ее возможностях управления компьютером.
Коротко о главных фичах UWP
Universal Windows Platform включает все те передовые возможности и сервисы, которые зарекомендовали себя еще в Metro и Windows RunTime. Это живые плитки, информация на экране блокировки, соответствующая текущему времени и зоне пребывания устройства, всплывающие уведомления, в необходимый момент напоминающие пользователю о разного рода событиях в системе, Action Center, позволяющий настраивать всплывающие уведомления и другой контент, с которым юзеру надо взаимодействовать; выполнение приложения в фоновом потоке, откуда его можно всегда вызвать или восстановить посредством триггеров, происходящих при определенных условиях, удобных пользователю. Твое приложение может взаимодействовать с другими процессами посредством контрактов; приложение может взаимодействовать также со всем окружающим миром: им можно управлять голосовыми командами, оно может общаться с другими устройствами по Bluetooth и многое другое.
Взаимодействие с аппаратными платформами
Помимо хороших новостей, с которыми я познакомил тебя во введении, есть одна плохая. На самом деле она скорее средняя :). Дело в том, что приложения для UWP не «унаследованные», их придется писать с нуля. То есть ради благого дела исполнения одного бинарника на всех устройствах придется поднапрячься. Кстати, когда я говорю про «один бинарник», я немного лукавлю. Когда разработчик заливает свое приложение в общий для всех платформ Store, находящийся в облаке компилятор .NET Native (подробнее см. в предыдущей статье) компилирует приложение под все поддерживаемые Windows 10 микропроцессоры.
Между аппаратными платформами приложение сохраняет не только общий функциональный код, но и общий пользовательский интерфейс. Однако различные устройства предлагают наличие определенных хардварных расширений: у смартфона по сравнению с PC это акселерометр, Touch-screen (есть на PC, но далеко не на всех), GPS, компас, аппаратная кнопка BACK и прочее. В то же время у смартфона отсутствует жесткий диск, CD/DVD/Blue-ray. С такими аппаратными возможностями позволяют работать специально заточенные под определенный вид девайса расширения — SKU: Desktop SKU, Mobile SKU, IoT SKU, Xbox SKU и так далее.
Хакер #202. Скажи нет большому брату!
Если абстрактно представить устройство операционной системы Windows 10, то мы увидим расширения SKU под ядром, которые и являются ядерными компонентами. Отсюда следует, что эти расширения подобны драйверам устройств. С другой стороны над ядром находится Universal Windows Platform — универсальная платформа для выполнения специальных приложений.
Обновление UWP и операционной системы
Теперь, как обещает Microsoft, в обозримом будущем она не будет выпускать новые версии операционной системы, будут выходить только бесплатные обновления. Также обновления могут коснуться платформы UWP. Поэтому сейчас разработчик ставит целью создавать приложение не для определенной версии операционной системы, а в первую очередь для конкретного оборудования и универсальной платформы (необходимая версия которой указывается в манифесте приложения и публикуется в Windows Store). При этом, поскольку операционная система и платформа выполнения представляют разные уровни, они могут обновляться независимо друг от друга. Таким образом, актуальность платформы выполнения не зависит от актуальности операционной системы, и наоборот. Это также предполагает дополнительный уровень безопасности.
Если продолжить нашу абстрактную модель операционной системы,
то мы увидим, что над UWP находятся расширения SDK (extension SDK), или, по-другому, расширения платформы, каждое из которых служит для взаимодействия с аппаратным обеспечением определенного устройства, подобно SKU, только последний взаимодействует в пространстве ядра, а расширения SDK — в пространстве пользователя. А уже над этими расширениями находится специфическое приложение.
Инструменты разработки для UWP
Visual Studio 2015 — если ты читал мои предыдущие статьи, то понимаешь, почему VS я считаю первым и главным (что приятнее всего — бесплатным) инструментом разработки. Впрочем, если ты не читал моих статей вовсе, ты все равно это понимаешь :).
На втором месте у нас расположен Blend. Теперь он имеет более схожий с Visual Studio интерфейс. Blend в большей степени ориентирован на дизайнеров. В нем разработчик может настраивать как сами объекты, так и их привязку, состояния, переходы, анимации и прочее.
Непосредственно для написания кода ты можешь использовать язык, с которым лучше всего знаком, неважно, веб-программист ты или прикладной. Как и в Windows 8, у тебя в распоряжении C# и Visual Basic.NET вместе с XAML, JavaScript с HTML, Visual C++ с DirectX и/или XAML. Так что простор для творчества очень широк.
Проектирование UWP-приложений
Чтобы оптимизировать разработку для огромного парка сильно различающихся устройств, в Windows 10 добавлены новые универсальные элементы управления, макеты, механизмы для адаптирования UI под различные девайсы, на которых может запускаться разрабатываемое приложение.
Во многих случаях Windows 10 подгоняет приложения под конкретное устройство автоматически. Кроме того, универсальные элементы управления и панели макетов помогают тебе оптимизировать интерфейс для экранов с различным расширением; общие элементы ввода позволяют получать данные от всех типов устройств ввода: мыши, клавиатуры, touch-screen, указателя или джойстика от Xbox.
Проектирование пользовательских интерфейсов в UWP происходит в эффективных пикселях, а не в физических. Это позволяет добиться относительно одинакового отображения элемента на разных по размеру и плотности экранах. Таким образом, на PC элемент может быть размером 175 х 175 физических пикселей, тогда как на планшете 150 х 150, а на моноблоке Surface Hub — 200 х 200.
Новые элементы управления
Для обеспечения совместимости с разными экранами UWP содержит новые элементы управления, среди которых Calendar, Split View, Pivot Control (последний был и раньше, но только в Windows Phone). Адаптивные панели позволяют автоматом настраивать размер и позицию дочерних элементов на основе имеющегося свободного пространства: StackPanel размещает дочерние элементы последовательно — один за другим, в столбец или строчку. Grid размещает свои элементы в ячейки таблицы. Новая адаптивная панель RelativePanel позволяет размещать дочерние элементы в соответствии с заданными относительными отступами и размерами.
Кроме того, UWP содержит адаптивные триггеры (AdaptiveTriggers), позволяющие при определенных размерах окна показывать и/или скрывать какие-то элементы управления.
В качестве примера можно привести стандартный почтовый клиент Mail for Windows 10. В нем при расширении окна свыше 720 пикселей (wideView) отображаются полные названия аккаунтов электронной почты, а при сужении окна (narrowView) — только иконки. Эти условия прописываются в XAML-коде.
Универсальные методы ввода организованы благодаря следующему набору API:
CoreIndependentInputSource предоставляет API для «сырого» ввода, который может происходить из главного или фонового потоков;
PointerPoint объединяет прикосновения, ввод с помощью мыши, ручки в один набор данных, состоящий из интерфейсов и событий, который может быть обработан в главном или фоновом потоках;
PointerDevice — API, который позволяет определить устройство ввода на основе предоставляемых им возможностей и использовать их;
InkCanvas и InkPresenter — новые XAML-элементы управления, которые позволяют взаимодействовать с устройствами, имеющими E Ink экран (уж не знаю, зачем Юрий сделал тут ссылку на Википедию, у нас что, читатели рубрики «Кодинг» не знают про электронные чернила? 🙂 — Прим. ред.).
Планирование
Планирование приложений, в частности UWP, состоит из пяти этапов:
• концепт;
• структура;
• динамика;
• визуализация;
• прототип.
На первом шаге мы собираем все идеи планируемого приложения, выделяем основные и определяем главную цель.
На этапе определения структуры определяем шаги, которые надо выполнить для достижения главной цели.
На этапе определения динамики делаем наброски (например, карандашом на бумаге), по которым процесс достижения цели можно увидеть по шагам — в динамике. С помощью визуализации уже можно представить внешний вид твоего будущего приложения. То есть надо отрисовать уже рабочие элементы.
При прототипировании можно воспользоваться бумажными рисунками (переходить на каждый в соответствии с предполагаемым ходом выполнения программы), а можно разработать простое приложение, которое не будет повторять функциональность целевого приложения, а только покажет следование по пользовательскому интерфейсу. На этом этапе можно понаблюдать, как идеи будут работать в приложении.
Программирование UWP-приложений
Работа с камерой в UWP
Существует огромное множество способов и путей разработки классных приложений для UWP. Как мы уже говорили, для этого доступен любой современный язык программирования, имеется большое число инструментов, компонентов и сервисов для улучшения приложений. Рассмотрим пример работы с камерой с помощью C#. У нас есть два варианта: классы CameraCaptureUI и MediaCapture. С помощью первого можно быстро создать простенький захватыватель снимков, однако, если тебе нужен полнофункциональный фотоаппарат со всяким фичами и настройками, следует воспользоваться вторым. Для примера мы возьмем класс CameraCaptureUI. Он вызывает стандартный UI операционной системы, получает с его помощью фото/видео и возвращает его в наше приложение (см. проект CamCap в материалах к номеру).
Итак, создав новый универсальный проект для Windows 10, с помощью XAML-редактора или визуального редактора добавим на главную страницу две кнопки: первая будет служить для создания снимка, а вторая — для начала/прекращения записи видео. Предварительно надо создать StackPanel и прикрепить ее к правой границе страницы, чтобы сгруппировать элементы-кнопки. Последние надо поместить внутрь StackPanel. Чтобы была реакция на нажатие кнопок, у каждой из них обрабатывается событие Click. Приведу XAML-код для одной из кнопок (создание фото), для второй — по подобию:
<Button
x:Name="buttonPhoto"
Content="Make photo"
HorizontalAlignment="Left"
Margin="0,198,0,0"
VerticalAlignment="Top"
Click="buttonPhoto_Click"
/>
Так как снимки должны осуществляться асинхронно, подключи пространство имен: System.Threading.Tasks. Далее, чтобы использовать CameraCaptureUI, надо подключить пространство имен Windows.Media.Capture, а для возможности управлять возвращенным файлом изображения нужно пространство имен Windows.Storage. Дополнительно нам понадобится изображение — объект класса Image, куда будет возвращен сделанный снимок, поэтому в разметку добавь:
<Image
x:Name="imageControl"
Width="300"
Height="300"
/>
Для возможности работы с этим классом нужно добавить пространство имен Windows.UI.Xaml.Media.Imaging. Чтобы сделать фото, используя стандартный UI, надо создать объект класса CameraCaptureUI, также можно сразу настроить свойства возвращаемого изображения (PhotoSettings). В нашем случае указывается формат изображения и размер окна для обрезки изображения.
После задания свойств асинхронно вызывается метод CaptureFileAsync объекта CameraCaptureUI, он в качестве параметра принимает режим захвата (фото или видео), в текущем случае передается флаг CameraCaptureUIMode.Photo. В результате его успешного выполнения снимок сохраняется в объекте класса StorageFile. После получения снимка с фотокамеры CameraCaptureUI позволяет обрезать полученное изображение (при положительном значении AllowCropping). Если юзер отменяет процесс получения снимка, то программа получает null и заканчивает выполнение метода.
Имея изображение в объекте StorageFile, для подготовки картинки к выводу в компонент Image надо преобразовать ее в объект SoftwareBitmap. Для этого сначала необходимо открыть поток из файла изображения, затем уже из потока декодировать картинку в битмап. В свою очередь, для работы с потоками и битмапами надо подключить пространства имен: Windows.Storage.Streams, Windows.Graphics.Imaging. Открытие потока, создание декодера на основе потока и собственно декодирование — асинхронные операции. Затем надо преобразовать получившееся изображение SoftwareBitmap в формат BGRA8. Это достигается с помощью статического метода SoftwareBitmap — Convert. Ему передаются исходное изображение, целевой формат и целевое состояние альфы. На выходе получается новый, конвертированный объект SofwareBitmap.
Далее создается объект класса SoftwareBitmapSource, которому асинхронно с помощью его метода SetBitmapAsync передается содержимое конвертированного изображения. Теперь последний можно использовать в качестве источника для визуального компонента класса Image.
Следующая наша задача — захват видео с помощью CameraCaptureUI. Этот класс добавляет интерфейс для редактирования захваченного видео. Но обо всем по порядку.
Во-первых, в XAML-разметку добавь проигрыватель — объект класса MediaElement. Нам понадобятся два пространства имен: Windows.Media.Editing и Windows.Media.Core. Во время нажатия на кнопку Make video сначала надо создать объект CameraCaptureUI, настроить свойства (на этот раз VideoSettings). Далее с помощью метода CaptureFileAsync (в качестве параметра передать CameraCaptureUIMode.Video) получаем «сырое» видео, помещаем его в объект класса StorageFile. Затем нам понадобятся два объекта классов: MediaComposition и MediaStreamSource. Первый содержит итоговое видео, а второй — поток, отображаемый в MediaElement. Когда мы имеем ненулевой StorageFile, мы можем извлечь из него видео (объект MediaClip): MediaClip mediaClip = await MediaClip.CreateFromFileAsync(videoFile). Далее мы добавляем клип к композиции (MediaComposition). Затем с помощью метода GeneratePreviewMediaStreamSource преобразуем композицию из клипов в поток, который посредством метода SetMediaStreamSource выводим в MediaElement.
Второй вариант предполагает использование класса MediaCapture. Он предоставляет широчайшие возможности для настройки работы камеры, захваченных материалов и их постобработки. Он позволяет выбрать камеру (в ноуте камера обычно одна, эта опция имеет смысл для смартов и планшетов), работать с высоким диапазоном яркости — HDR, определять ориентацию устройства, добавлять эффекты к фото/видео, анализировать изображения и/или видео, в том числе для определения человеческого лица, создавать последовательность фото с разными настройками и многое другое.
Кроме того, с помощью средств работы с аудио/видео, входящих в Windows 10, можно запросто написать свой редактор видео/аудио, а также конвертер между форматами.
Геолокация и карты
Пространство имен Windows.UI.Xaml.Controls.Maps содержит класс MapControl. Чтобы отобразить карту в своем UWP-приложении, надо в XAML-разметку (или в визуальном дизайнере) добавить элемент управления MapControl (см. проект MapControlComp в материалах к номеру):
<Maps:MapControl
x:Name="MapControl1"
ZoomInteractionMode="GestureAndControl"
TiltInteractionMode="GestureAndControl"
MapServiceToken="key"
/>
Элемент MapControl по умолчанию поддерживает перетаскивание камеры, зуминг с помощью колесика мыши, а на сенсорном экране соответствующие жесты. Обрати внимание на значение свойства MapServiceToken, здесь должно быть значение, полученное от Bing Maps Developer Center. Если его не будет, внизу карты высветится лейбл: «Не указан параметр MapServiceToken».
Чтобы задать начальные координаты, над которыми появится камера, надо свойству Center объекта MapControl присвоить объект класса GeoPoint, полученный из объекта класса BaseGeoposition, для которого указываются значения свойств широты и долготы (Latitude, Longitude).
.
Чтобы получить текущие координаты устройства, достаточно вызвать метод GetGeopositionAsync объекта Geolocator:
Geolocator geolocator = new Geolocator();
Geoposition pos = await geolocator.GetGeopositionAsync();
Geopoint myLocation = pos.Coordinate.Point;
MapControl1.Center = myLocation;
Через свойства объект MapControl можно тонко настроить для получения более удобного вида: задать угол поворота, масштаб, стиль карты, уровень зума, цветовую схему и многое другое.
Кроме того, у компонента MapControl есть еще два режима просмотра местности. Это просмотр панорамы улиц StreetSide View (есть не для всех точек планеты) и просмотр местности в перспективе — 3D View. Для переключения в каждый из режимов на основную страницу приложения я добавил две кнопки, поместив их в StackPanel.
Итак, чтобы переключиться в режим 3D View, надо написать совсем немного кода. Во-первых, нужно проверить, поддерживается ли данный режим на текущем устройстве, затем у MapControl включить стиль просмотра улиц в 3D — Aerial3DWithRoads, далее создать Geopoint, определяющий текущие координаты (центр экрана). Следующим действием создадим дополнительный объект MapScene, он нужен для создания перспективы. У этого объекта несколько конструкторов, в нашем случае CreateFromLocationAndRadius. Ему передаются: заданный ранее центр экрана, обозреваемый радиус в метрах, направление камеры просмотра в градусах, наклон камеры.
Последним действием вызывается метод TrySetSceneAsync объекта класса MapControl, который получает созданный на предыдущем шаге MapScene и тип анимации перехода, а выполняет переключение вида в 3D. Как оказалось, в Bing не для каждого города есть просмотр в 3D, кое-где здания и местность остаются двумерными текстурами.
В режиме StreetSide View можно просматривать фотопанораму вокруг заданных координат (разумеется, только в тех местах планеты, куда заезжали фотомашины Bing). Чтобы включить режим StreetSide View, необходимо вначале проверить, поддерживает ли девайс этот режим; если поддерживает, то создать BasicGeoposition, потом на его основе Geopoint, содержащий нужные координаты (в примере указаны координаты Эйфелевой башни). Затем асинхронно создается объект класса StreetsidePanorama с помощью конструктора FindNearbyAsync. В качестве параметра последний принимает объект Geopoint. Следующим действием объект панорамы проверяется на равенство null, если это не так и объект успешно создан, тогда на его основе строится объект StreetsideExperience, который представляет панорамный вид в указанной локации. Последним действием показываем сгенерированный StreetsideExperience в MapControl, присвоив его свойству CustomExperience.
При работе с картами у тебя также есть возможность ставить маркеры (объекты класса MapIcon), отмечать определенные точки, располагать полигоны (MapPolygon), с помощью линий строить многоугольники (MapPolyline). Для этого надо создать объект нужного класса визуального элемента карты и определить объект или список (List) объектов класса BasicGeoposition, которые представляют пары координат. Для визуального элемента можно настроить свойства, например толщину контурной линии, позицию по оси Z (определяет порядок наложения объектов друг на друга), изображение, цвет. А для отображения его на карте (объект MapControl) надо добавить в ее коллекцию объектов созданный элемент.
Win 2D
В DirectX 11 появился Direct2D — новый интерфейс для работы с двумерной графикой. Что примечательно, в DirectX до 8-й версии (до 2000 года) был интерфейс для 2D-графики — DirectDraw, но его перестали развивать. Приоритетным направлением тогда стал 3D.
Однако в наши дни, с появлением мобильных девайсов впечатляющей мощности, интерес к двумерной графике и играм снова ожил. Поэтому Microsoft решила сделать новый современный механизм работы с двумерной графикой и включить его в состав DirectX. Так появился Direct2D. Но он предназначался только для C++, равно как и остальные компоненты DirectX, основанные на COM, был сложен в использовании и очень многословен. Из-за этого он не получил признания и распространения.
В результате в 12-й версии DirectX Microsoft добавила надстройку над Direct2D под названием Win2D. Чтобы программировать с ее помощью, не нужно писать избыточного кода, детали скрыты от глаз разработчика. Надстройка Win2D доступна программистам как C++, так и C#. Она включает все возможности Direct2D, а также много уже заготовленных вещей: эффекты камеры, видеоэффекты, патикловые эффекты, работу со слоями, геометрические фигуры и операции. В итоге Win2D представляет собой Windows Runtime API для режима непосредственного вывода двумерной графики с аппаратным ускорением. Win2D реализован как компонент, легко добавляемый в XAML-разметку.
Win2D — интересная и полезная тема, но мы вынуждены перенести ее обсуждение на другой раз. Удачи тебе в деле освоения по-настоящему кросс-платформенных приложений!