В последние дни я начал работать с Prism для универсальных приложений Windows и решил поделиться с вами своим опытом. Что такое призма? Если вы являетесь давним разработчиком Microsoft, вы, вероятно, уже знаете это: это очень популярная инфраструктура MVVM (Model-View-ViewModel), созданная подразделением Patterns & Practices в Microsoft с целью помочь разработчикам реализовать Шаблон MVVM в своих приложениях и для поддержки наиболее распространенных сценариев.
Недавно подразделение выпустило версию Prism , полностью совместимую с средой выполнения Windows и, следовательно, с разработкой универсальных приложений для Windows: цель этой серии постов в блоге — узнать, как использовать ее для этого сценария и как она может помочь Вы разрабатываете приложение MVVM.
Я не буду подробно обсуждать преимущества использования шаблона MVVM: я уже говорил об этой теме в серии статей о Caliburn Micro .
Призма против других наборов инструментов и структур
Как Prism сравнивается с другими популярными наборами инструментов и средами MVVM, такими как MVVM Light и Caliburn Micro? Немного поиграв с этим, я пришел к выводу, что он пытается взять лучшее из обоих миров. Определенно, это гораздо больше похоже на Caliburn Micro, чем на MVVM Light: на самом деле, мы говорим о платформе, которая предлагает множество встроенных классов и помощников, которые полезны для управления конкретными сценариями платформы (такими как навигация, управление состоянием, и т.д.). Более того, подобно Caliburn Micro, он использует некоторые специальные классы, которые заменяют собственные (например, класс App или класс Page), который действует как загрузчик для правильной настройки всей инфраструктуры, необходимой Prism для правильной работы.
Однако одним из недостатков Caliburn Micro является то, что он не идеален для разработчиков, которые впервые работают с MVVM: несмотря на то, что он очень мощный, все соглашения об именах, как правило, скрывают все основные понятия, лежащие в основе шаблона, такие как привязка, DataContext или использование интерфейса INotifyPropertyChanged. Вместо этого Prism, за исключением некоторых незначительных сценариев (подробности мы увидим позже), по-прежнему основывается на стандартных основах MVVM, поэтому в нем используются концепции, которые должны быть знакомы каждому разработчику XAML, такие как привязка или команды.
Настройка проекта
Давайте посмотрим, как создать наше первое универсальное приложение для Windows с помощью Prism: первый шаг — создать новый проект универсального приложения для Windows в Visual Studio, который создаст обычное решение с общим проектом, Windows 8.1 и Windows Phone 8.1. , Если вы знакомы с разработкой универсальных приложений для Windows, вы будете знать, что общий проект — это не настоящая библиотека, а просто набор общих ресурсов (таких как классы, ресурсы и элементы управления XAML), которые связаны с двумя другими проекты. Следовательно, вы не можете добавить ссылку на стороннюю библиотеку в общий проект: ссылки берутся непосредственно конкретными проектами основных платформ. Первый шаг — с помощью NuGet установить Prism.StoreApp как в Windows, так и в проекте Windows Phone. библиотека, которая является версией Prism, специфичной для приложений Магазина Windows.
Второй шаг является необязательным, но настоятельно рекомендуется, поскольку мы собираемся использовать этот подход в следующих примерах: когда мы говорили о Caliburn Micro, мы узнали немного больше о внедрении зависимостей, который является способом создания объектов во время выполнения вместо времени компиляции. Плюсы этого подхода в том, что мы можем легко изменить реализацию класса (например, потому что мы хотим заменить реальный класс на фальшивый, который предоставляет фальшивые данные во время разработки), без необходимости изменять все модели ViewModel, которые используй это.
Кроме того, Prism поддерживает внедрение зависимостей, и это лучший способ управлять зависимостями ViewModels от других служб нашего приложения (например, службы навигации или службы данных, которая извлекает данные нашего приложения и т. Д.). Наиболее широко используемым контейнером внедрения зависимостей для Prism является Unity, который также предоставляется подразделением Pattern & Practices Microsoft: следующим шагом, следовательно, является повторное использование NuGet для установки Unity в обоих проектах. Важно подчеркнуть, что вам нужно включить опцию для расширения поиска также в предварительных выпусках: последняя стабильная версия, на самом деле, пока не поддерживает Windows Phone 8.1, поэтому вы получите ошибку при установке, если Вы пытаетесь добавить это.
Преобразование приложения в приложение Prism
Первым шагом по преобразованию приложения Universal в приложение на основе Prism является настройка загрузчика: под этим термином я подразумеваю процедуру, которая требуется средой для правильной инициализации всей инфраструктуры, необходимой для работы. В универсальных приложениях Windows загрузчик — это сам класс App : мы собираемся переопределить класс App , чтобы он больше не наследовал от собственного класса Application , а от класса Prism, называемого MvvmAppBase .
Для этого необходимо выполнить два шага: первый — изменить определение класса App в XAML, в файле App.xaml. Вам нужно будет добавить новое пространство имен, в котором определен класс MvvmAppBase : пространство имен — Microsoft.Practices.Prism.Mvvm. Второй шаг — заменить базовый тег Application на тег MvvmAppBase . Вот как будет выглядеть файл App.xaml в конце:
<mvvm:MvvmAppBase x:Class="PrismDemo.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:PrismDemo" xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm"> </mvvm:MvvmAppBase>
Вместо этого вторым шагом является изменение кода класса App , поэтому вам нужно отредактировать файл App.xaml.cs: первое, что нужно сделать, это заменить класс, от которого наследуется объект App, который не является больше приложение, но MvvmAppBase . Затем вам нужно удалить весь код и оставить только конструктор приложения : фактически Prism предлагает свой собственный способ управления событиями жизненного цикла различных приложений (такими как запуск, активация, приостановка и т. Д.).
Вот как выглядит базовый класс App для проекта Prism:
sealed partial class App : MvvmAppBase { public App() { this.InitializeComponent(); } }
Мы еще не закончили настройку загрузчика, но, во-первых, нам нужно создать нашу первую страницу, чтобы было легче понять следующие шаги. Как я уже упоминал ранее, одним из преимуществ Prism перед Caliburn является то, что, несмотря на то, что он является мощной платформой, он не скрывает всей базовой инфраструктуры MVVM. Однако есть исключение: как в Caliburn, соединение между View и ViewModel выполняется с использованием соглашения об именах. Вы можете также использовать другой подход, если хотите (например, использование ViewModelLocator или прямую привязку ViewModel в качестве контекста данных View), но соглашение об именовании является наиболее простым в использовании, чтобы воспользоваться всеми функциями Prims. Соглашение об именах очень простое, и оно напоминает соглашение, используемое Caliburn: вам нужно поместить ваши ViewModels в папку вашего проекта с именемViewModels , в то время как виды будут помещены в папку под названием Views . Поскольку вы работаете с универсальным приложением для Windows, обычно вы собираетесь создать папку ViewModels в общем проекте (так как ViewModels будет совместно использоваться на двух платформах), в то время как папка Views будет создаваться в проекте, специфичном для платформы. , так что вы можете оптимизировать пользовательский интерфейс для двух платформ.
Также существует другое соглашение об именах, которое касается имен файлов:
- Вид должен заканчиваться суффиксом страницы (например, MainPage ).
- ViewModel должно иметь то же имя View, плюс суффикс ViewModel (так, например, ViewModel, подключенный к странице с именем MainPage, будет называться MainPageViewModel ).
Теперь, когда вы создали свою первую страницу приложения, вам нужно будет сказать Prism, что это страница по умолчанию, которую необходимо загрузить при запуске приложения. Вы достигнете этой цели, переопределив в классе App один из методов, предлагаемых классом MvvmAppBase , а именно OnLaunchApplicationAsync () . Вот как это выглядит в типичном приложении Universal для Windows:
protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args) { NavigationService.Navigate("Main", null); return Task.FromResult<object>(null); }
В этом методе используется один из встроенных помощников, предлагаемых Prism, о которых мы подробно расскажем в следующих статьях: это класс с именем NavigationService , который используется для навигации с одной страницы на другую. Для перехода на другую страницу необходимо использовать метод Navigate () , который принимает в качестве первого параметра имя страницы, которое является именем представления без суффикса страницы : в предыдущем примере, передавая в качестве параметра значение Main мы предполагаем, что в папке Views нашего проекта у нас есть страница с именем MainPage.xaml . На данный момент не обращайте внимания на второй параметр, который просто имеет значение null: это необязательный параметр, который мы можем передать на целевую страницу.
Последняя строка кода, выполняемая операцией, является «обходным путем»: как вы можете видеть, метод OnLaunchApplicationAsync () возвращает задачу , так что вы можете выполнять внутри нее асинхронные операции. Поскольку в этом случае мы не выполняем ни одного из них, мы возвращаем «поддельный», используя метод Task.FromResult () и передавая значение null в качестве параметра.
Настройка внедрения зависимости
Последний шаг перед началом реальной работы над приложением — это настройка контейнера внедрения зависимостей: как уже упоминалось, мы будем использовать Unity. Инициализация контейнера выполняется в методе, предложенном MvvmAppBase, который называется OnInitializeAsync () , который выполняется, когда приложение инициализируется в первый раз. Подход здесь тот же, что мы видели в Caliburn: мы можем зарегистрировать собственные сервисы, чтобы они автоматически добавлялись в ViewModels, когда мы собираемся их использовать. Тем не менее, мы также должны зарегистрировать некоторые встроенные сервисы, чтобы мы могли использовать их в других моделях представления: это NavigationService(который мы уже видели и он используется для навигации с одной страницы на другую) и SessionStateService, который мы подробно рассмотрим в другом посте. На данный момент важно просто знать, что это помогает разработчику облегчить управление приостановкой и завершением приложения.
Если у вас есть некоторый опыт работы с Caliburn или MVVM Light, вы будете знать, что одним из необходимых шагов для правильной настройки внедрения зависимостей является регистрация внутри контейнера (который является классом, который заботится о диспетчеризации объектов при необходимости). , все ViewModels проекта. С Prism это не требуется: благодаря ранее описанному соглашению об именах, мы можем сказать Prism (используя класс ViewModelLocatorProvider ), что мы хотим автоматически регистрировать все доступные ViewModel.
Вот как выглядит полный файл App.xaml.cs:
sealed partial class App : MvvmAppBase { IUnityContainer _container = new UnityContainer(); public App() { this.InitializeComponent(); } protected override Task OnLaunchApplicationAsync(LaunchActivatedEventArgs args) { NavigationService.Navigate("Main", null); return Task.FromResult<object>(null); } protected override Task OnInitializeAsync(IActivatedEventArgs args) { // Register MvvmAppBase services with the container so that view models can take dependencies on them _container.RegisterInstance<ISessionStateService>(SessionStateService); _container.RegisterInstance<INavigationService>(NavigationService); // Register any app specific types with the container // Set a factory for the ViewModelLocator to use the container to construct view models so their // dependencies get injected by the container ViewModelLocationProvider.SetDefaultViewModelFactory((viewModelType) => _container.Resolve(viewModelType)); return Task.FromResult<object>(null); } }
В предыдущем коде вы видите три необходимых шага для настройки внедрения зависимости:
- Мы создаем свойство с типом IUnityContainer и создаем новый экземпляр.
- Мы регистрируем, используя RegisterInstance <T> () , ранее описанные SessionStateService и NavigationService .
- Используя SetDefaultViewModelFactory () метод ViewModelLocationProvider класса, мы можем автоматически регистрировать каждый ViewModel мы имеем в нашем проекте, так что он может быть автоматически подключен к View , когда требуется ..
Теперь мы определили правильную инфраструктуру, требуемую Prism: есть только один последний шаг, который должен сказать каждому View в нашем приложении, какой ViewModel использовать. Мы достигаем этого, добавляя в класс Page в XAML свойство, предлагаемое Prism с именем AutoWireViewModel , которое предлагается классом ViewModelLocator : устанавливая для него значение True , мы включаем соглашение об именах, поэтому представление автоматически будет искать его собственный ViewModel и назначит его как DataContext. Вот как выглядит страница в приложении Prism:
<Page x:Class="PrismDemo.Views.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:PrismDemo.Views" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mvvm="using:Microsoft.Practices.Prism.Mvvm" mc:Ignorable="d" mvvm:ViewModelLocator.AutoWireViewModel="True" </Page>
Завершение
Пока что мы только что увидели, как работает Prism и как настроить проект. В следующем посте мы начнем создавать приложение по-настоящему, увидев, как использовать привязку и как определять команды для управления взаимодействием с пользователем. Если вы хотите получить максимальную отдачу от реального проекта, вы можете найти образец, который мы собираемся использовать в следующем посте на GitHub, по адресу https://github.com/qmatteoq/Prism-UniversalSample