Хотел бы закодировать разработчиков WPF от боязни чего-то нового, рассказав про отличия, которые ожидают их при разработке приложений под универсальную платформу Windows. Так что ставьте банки перед монитором, я начинаю давать установку.
Какие-то изменения в языках программирования и платформах происходят постоянно. Представьте себе на минуту, что выйдет C# версии 10 и все. Это последняя версия. Представили? Я представил. И в моем представлении если это и случится когда-нибудь, то эта последняя версия языка будет регулярно обновляться.
Были «чудесные» времена, когда у меня немного разбегались глаза от различий в коде (даже в коде XAML): WPF, Silverlight, Windows Phone, потом WinRT, а теперь еще и UWP. Сколько разработчиков никогда не путаются? Я думаю, что большинство разработчиков не держат все в памяти. Достаточно держать в памяти основные концепты работы. Когда дело касается кодирования, то используются вспомогательные инструменты вроде IntelliSense, Blend и т.п. Никуда не уйти и от использования сниппетов.
По каким причинам происходят изменения:
1. Где-то сидит вредный дядя, который ждет момента, когда все привыкнут к платформе/среде разработки. И тогда он что-то меняет.
2. Усовершенствования/новый функционал.
3. Отзывы пользователей или разработчиков (не понравилось и все тут). Исправление ошибок.
4. Аппаратная часть совершенствуется. Акцент на энергосбережение, на производительность или же на красивые эффекты.
5. Что-то глобальное. Например, последнее объединение платформ в UWP или что-то вроде «Мы хотим чтобы на C# писали под все платформы сразу, минуя Xamarin, поэтому добавили вам новые аналогичные другим платформам контролы». Кто знает, может через несколько лет будет и такое.
6. Ваш вариант напишите в комментариях.
Для чего разработчикам нужно знание UWP? Да, хотя бы из-за того, что в .Net приложениях можно будет в скором времени использовать API и сервисы UWP. Все это может в скором времени стать возможным с помощью Project Cenntenial.
Так что вполне можно начать знакомиться с новой платформой. Давайте я сделаю небольшой экскурс, описав некоторые отличия.
Начну с того, что приложения UWP обладают кое-чем, чего нет у классических приложений Windows – у них есть App Model. Что такое App Model? Это своеобразный регламент. Описание всех возможностей приложения — его прав доступа, способа установки, обновления, хранения информации и т.п.
У приложений Windows Store, точно так же как и у приложений UWP есть файл манифеста, в котором описаны все возможности и права приложения. Это файл Package.appxmanifest. Его можно редактировать как в графическом редакторе, так и в виде кода XML. Скриншот графического редактора смотрите ниже.
Элементы управления
Если вы помните, то совсем недавно у Windows 8 и 8.1 была Charm panel – волшебная панелька:
Сейчас же вместо нее используются более привычные для WPF разработчиков контролы:
Здесь новым контролом является ContentDialog, который блокирует приложение, примерно так же, как блокирует его MessageBox.
Кроме того в UWP более привычная для разработчиков WP навигация:
Что может показаться интересным, так это то, что некоторые элементы управления могут иметь различный внешний вид при отображении на различных устройствах. Простыми словами, контрол может выглядеть немного иначе, например, при отображении на десктопе и на мобильном устройстве.
В целом, я так полагаю, среднестатистический разработчик уже давно привык большому разнообразию контролов. Освоение новых трудностей вызвать не должно.
Разработка под различные устройства
Постараюсь разобрать то, что для WPF разработчика будет необычным. Например, это то, что при разработке приложений Windows 8.1 можно было в одном решении разрабатывать одновременно и под телефон и под десктоп.
В таком случае создавалось 3 проекта. В приложениях WP и WinRT хранился xaml код «вьюшек» и какой-то особый код под устройства, а в общем проекте хранился общий код xaml и общий для двух проектов код C#.
Сейчас же, так как платформа UWP универсальная, то для каждого типа устройств можно создать папку, в которую можно поместить «вьюшку» — т.е. xaml файл с дизайном под параметры устройства.
Подробнее здесь:
3 способа задать разметку для различных устройств в C#/XAML приложениях Windows UWP
Жизненный цикл
Есть старая шутку про формулу-1: «У Ральфа Шумахера два положения педали – включено и выключено. Остальными положениями можно пренебречь».
Этой шуткой я могу немного подколоть классические приложения .Net. Они либо работают, либо не работают. В приложениях Store все немного иначе. У них кроме состояний «Включено/выключено» есть еще и промежуточное состояние «Приостановлено». Жизненный цикл приложений 8.x и UWP отображен на следующей картинке:
Подробнее здесь:
Application Lifecycle в приложениях Windows 8.1 и UWP
Триггеры и фоновые задания
Приложения .Net могут быть либо исполняемыми файлами либо могут быть службами/сервисами. Это совершенно разные виды приложений. То есть не может быть такого, что приложение exe, но при этом оно работает в фоне. Нет, конечно же, приложение может работать в трее. Но фактически получается, что оно запущено и просто свернуто.
Что касается приложений 8.x и UWP, то они могут содержать в себе фоновые задания. Фоновые задания это некоторое подобие сервиса. То есть приложение может не работать, но в системе будет выполняться какая-то задача. Кроме того фоновая задача может «отлавливать» какие-то события в работе системы триггером.
Один из самых популярных триггеров это SystemTrigger. С помощью него приложение может выполнить какой-либо код при наступлении таких событий как: появление или пропажа интернета, изменение состояния сети, подключение или отключение пользователя, получение смс, изменение часовой зоны и т.п.
Также довольно популярны TimeTrigger и MaintenanceTrigger. Оба триггера выполняют какой-либо код с периодичностью в определенный промежуток времени. Промежуток времени должен быть не менее 15 минут. Отличие в то, что TimeTrigger требует регистрации приложения на экране блокировки, а MaintenanceTrigger-у требуется чтобы устройство работало не от батареи, а от сети.
В UWP появилось много новых триггеров. Взять, например такой вот интересный триггер как MediaProcessingTrigger, который позволяет приложению перекодировать мультимедиа в рамках фоновой задачи.
Использование библиотек
Если в классических приложениях вы использовали библиотеки DLL, то в приложениях 8.x и UWP вы сможете использовать как PCL, так и компонент среды выполнения WinMD. В чем отличие?
PCL (portable class library) может быть добавлена приложениям под различные платформы. И под .Net Framework различных версий, и под Windows 8.x и под WP, под UWP и даже под iOS/Android приложения Xamarin. То есть в эту библиотеку можно запихнуть какой-то общий платформонезависимый код.
WinMD может быть использован только под 8.x или UWP. Вне зависимости от языка, на котором написаны приложения, они могут работать с WinMD. Но сам WinMD в случае если он содержит в себе сложные вычисления лучше писать на C++ для достижения наилучшей производительности.
Впрочем, при разработке под UWP вы можете создать и библиотеку классов (DLL).
Работа с данными
В чем еще заключается отличие приложений UWP, так это в том, что они не работают с базами данных напрямую. То есть такие базы данных, как, скажем SQL Server или Oracle, расположенные на сервере организации, будут вам недоступны. Впрочем, это было бы странно, если бы пользователь скачивал из Store приложение, и приложение начинало бы работать с базой SQL Server-а, расположенной на сервере в локальной сети. Но вы сможете работать с данными, используя веб-сервисы. Есть возможность использовать для баз MySQL оракловский Connector/Net, но он на данный момент не поддерживает SSL и потому не особо интересен. Так что лучше не отклоняться от концепта использования сервисов для доступа к данным.
Для хранения информации внутри приложения вы можете использовать SQLite.
Хранения параметров приложения и работа с файлами
Хранение параметров приложения возможно не только на устройстве, но и в облаке. Таким образом, если запускать приложение на различных устройствах, то настройки везде будут одинаковыми.
Следующий небольшой сниппет сохраняет количество вызова кода в облаке:
int timescount = 0;
Object roamS = Windows.Storage.ApplicationData.Current.RoamingSettings.Values["times"];
if (roamS != null) timescount = (int)roamS;
timescount++;
Windows.Storage.ApplicationData.Current.RoamingSettings.Values["times"] = timescount;
Если заменить Windows.Storage.ApplicationData.Current.RoamingSettings на Windows.Storage.ApplicationData.Current.LocalSettings, то параметр будет сохранен локально на устройстве.
Настройки могут быть скомпонованы как в составные параметры, так и в контейнеры. Файлы точно так же как и настройки можно хранить как на устройстве в локальной папке, так и в облаке. Но кроме этого есть возможность хранить файлы во временной папке, которая при необходимости может быть очищена системой — ApplicationData.TemporaryFolder.
Кроме того можно получить доступ к папке, которая содержится в приложении с помощью
Windows.ApplicationModel.Package.Current.InstalledLocation
Доступ к файлам, хранящимся на дисках, тоже организован по особой модели. Содержимое папок документов, фотографий, видео и подобных может быть получено с помощью класса KnownFolders, но в таком случае необходима установка разрешений в манифесте. Доступ к какой-либо другой папке возможен только в случае, если пользователь выберет папку сам в процессе работы с приложением. Посещенные папки можно сохранять, дабы при повторном запуске приложения не заставлять пользователя делать лишние действия
var folderPicker = new Windows.Storage.Pickers.FolderPicker();
folderPicker.FileTypeFilter.Add(".jpg");
folderPicker.FileTypeFilter.Add(".jpeg");
folderPicker.FileTypeFilter.Add(".png");
folderPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
folderPicker.SettingsIdentifier = "picker2";
Windows.Storage.StorageFolder lastFolder = await folderPicker.PickSingleFolderAsync();
if (lastFolder == null) return;
String mruToken = Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(lastFolder);
Получить после этого последнюю сохраненную папку можно так:
String mruFirstToken = StorageApplicationPermissions.MostRecentlyUsedList.Entries.FirstOrDefault().Token;
lastFolder = await StorageApplicationPermissions.MostRecentlyUsedList.GetFolderAsync(mruFirstToken);
Привязки данных
Как в приложениях WPF, так и в приложениях UWP, а также при разработке под 8.x можно использовать привязки данных – {binding}. Но в UWP появились еще и компилируемые привязки – {x:bind} В чем отличие? Компилируемые работаю гораздо быстрее, а формируются/проверяются они во время компиляции а не во время запуска приложения. Также они строго типизированные.
Подробнее здесь:
Компилируемые привязки данных в приложениях Windows 10
Эффективные пиксели
Создавая приложение UWP, вы ведете разработку в эффективных пикселях, а не физических. Особый алгоритм масштабирования позволяет добиться того, что шрифт размера в 24 пикселя будет одинаково читаемым и на большом экране PC и на экране телефона.
Таким образом, получается, что разработчик может не заботится о плотности пикселей на различных устройствах или дистанции просмотра. Но он должен позаботиться о том, чтобы на устройствах с высоким разрешением изображения смотрелись качественно. Давайте рассмотрим папку Assets стандартного только что созданного универсального приложения:
Вы можете заметить, что у некоторых изображений имеется постфикс .scale-200. Это значит, что установлен размер масштабирования 200. Для примера возьмем файл Square44x44Logo.scale-200.png – его физический размер 88x88 пикселей. То есть масштаб 200%. Все доступные варианты это – 100, 125, 150, 200, 250, 300, 400.
Пример: если вы заходите создать вариант изображения для устройств с коэффициентом масштабирования 150, то вам нужно создать изображение размера 66x66 и назвать его Square44x44Logo.scale-150.png.
Это касается не только изображений, используемых в описании приложения, но и изображений, которые вы используете в UI.
Заключение
На самом деле все новые фичи UWP перечислять довольно долго (можно упомянуть о Adaptive triggers, Splitview, Ink, Map и т.п.). Надеюсь, что смог в короткой статье рассказать как о ключевых отличиях, так и о некоторых сходствах с WPF.
IL_Agent
Почему Ральфа, а не Михаэля? :)
Служба — это и есть исполняемый файл, зарегистрированный соответствующим образом. Какие ещё «разные виды» ?
Как так? )) А кому же ещё работать в фоне, как не exe?
А чем вам «запущено и просто свернуто» — не работа в фоне? Это более полноценная работа в фоне, нежели то, что предлагает WinRT / UWP.
asommer
(: У Ральфа более агрессивная манера езды. Бывают гонщики резкие на поворотах. Это шутка многим гонщикам подходит. А вот Шумми старший осторожный гонщик.
Вот знал что это место может вызвать вопросы. Выразился не очень красиво. Нужно было написать, что даже служба может или работать или не работать. Но в целом выходит вы подтверждаете, что если приложение работает в трее, то это оно полноценно работает. Т.е. фигурально выражаясь педаль газа нажата.)