Шаблон Model-View-ViewModel (MVVM) помогает разработчикам отделить бизнес-логику приложения и логику представления от его пользовательского интерфейса. Поддержание четкого разделения между логикой приложения и пользовательским интерфейсом помогает решать проблемы разработки и проектирования, упрощая тестирование, обслуживание и разработку приложения. Это также может улучшить возможность многократного использования кода и позволяет нескольким разработчикам легче сотрудничать при работе над одним проектом.
1. Введение
Используя шаблон MVVM, пользовательский интерфейс приложения и базовая презентация и бизнес-логика разделены на три компонента:
- Компонент представления инкапсулирует пользовательский интерфейс и логику пользовательского интерфейса.
- Компонент модели представления инкапсулирует логику представления и состояние.
- Уровень модели инкапсулирует бизнес-логику и данные приложения.
Существует несколько платформ для реализации шаблона MVVM в приложении Windows. Какая структура лучше всего подходит для вашего проекта, зависит от ваших требований. Для этого урока мы будем использовать MVVM Light , популярную и простую в использовании инфраструктуру MVVM.
Из этого туториала Вы узнаете, как создать универсальное приложение для Windows с поддержкой MVVM Light. Вы узнаете, как:
- создать универсальное приложение для Windows и добавить поддержку MVVM Light
- реализовать структуру каталогов
- добавить слой модели представления
- связать контекст данных
- реализовать службу обмена сообщениями для передачи сообщений между моделями представления
2. Настройка проекта
Шаг 1. Создание универсального приложения для Windows
Начнем с создания универсального приложения для Windows. Выберите « Новый проект» в меню « Файл» в Visual Studio. Разверните Шаблоны > Visual C # > Windows > Windows 8 > Universal и выберите Пустое приложение (Universal Windows 8.1) из списка шаблонов проектов. Назовите свой проект и нажмите OK, чтобы создать проект.
Это создает два новых приложения (Windows Phone 8.1 и Windows 8.1) и один общий проект. Проекты Windows Phone 8.1 и Windows 8.1 являются проектами, специфичными для платформы, и отвечают за создание пакетов приложений (.appx) для соответствующих платформ. Общий проект — это контейнер для кода, который выполняется на обеих платформах.
Шаг 2. Добавьте поддержку MVVM Light
Щелкните правой кнопкой мыши имя решения в обозревателе решений и выберите « Управление пакетами Nuget для решения» .
Выберите вкладку « Обзор » и выполните поиск MVVM Light . Выберите пакет MvvmLightLibs из результатов поиска. Проверьте проекты Windows 8.1 и Windows Phone 8.1 и нажмите « Установить», чтобы добавить библиотеки MVVM Light в приложения.
К этому моменту вы добавили поддержку MVVM Light для обоих ваших приложений.
3. Структура файла проекта
Универсальное приложение Windows, которое принимает шаблон MVVM, требует определенной структуры каталогов. На следующем снимке показана возможная структура файла проекта для универсального приложения Windows.
Позвольте мне познакомить вас со структурой проекта типичного приложения Univesal для Windows, в котором используется шаблон MVVM:
- Элементы управления . Этот каталог содержит повторно используемые элементы управления пользовательского интерфейса (независимые от приложений представления). Элементы управления для конкретной платформы добавляются непосредственно в проект для конкретной платформы.
- Строки : этот каталог содержит строки и ресурсы для локализации приложения. Каталог Strings содержит отдельные каталоги для каждого поддерживаемого языка. Например, каталог en-US содержит ресурсы для английского (США) языка.
-
Модели . В шаблоне MVVM модель инкапсулирует бизнес-логику и данные. Как правило, модель реализует средства, облегчающие привязку свойств к слою вида. Это означает, что он поддерживает уведомления «свойство изменено» и «коллекция изменено» через интерфейсы
INotifyCollectionChanged
иINotifyCollectionChanged
. - ViewModels : модель представления в шаблоне MVVM инкапсулирует логику представления и данные для представления. Он не имеет прямой ссылки на представление или каких-либо знаний о реализации или типе представления.
- Конвертеры : этот каталог содержит конвертеры значений. Преобразователь значений — это удобный способ преобразования данных из одного типа в другой. Он реализует интерфейс
IValueConverter
. - Темы : Каталог тем содержит ресурсы темы, имеющие тип
ResourceDictionary
. Специальные ресурсы платформы добавляются непосредственно в конкретный проект, а общие ресурсы добавляются в общий проект. - Сервисы : этот раздел может включать в себя классы для вызовов веб-сервисов, сервис навигации и т.д.
- Utils включает в себя служебные функции, которые можно использовать в приложении. Примеры включают
AppCache
,FileUtils
,Constants
,NetworkAvailability
,GeoLocation
и т. Д. - Представления : этот каталог содержит макеты пользовательского интерфейса. Специфические представления платформы добавляются непосредственно в конкретный проект платформы, а общие представления добавляются в общий проект.
В зависимости от типа представления имя должно заканчиваться:
- Окно , немодальное окно
- Диалог , (модальное) диалоговое окно
- Страница , просмотр страницы (в основном используется в приложениях Windows Phone и Windows Store)
- Представление , представление, которое используется как подпредставление в другом представлении, странице, окне или диалоге
Название модели представления состоит из имени соответствующего представления и слова «Модель». Модели представлений хранятся в том же месте в каталоге ViewModels, что и их соответствующие представления в каталоге представлений.
4. Добавление вида модели слоя
Уровень модели представления реализует свойства и команды, с которыми представление может связывать данные и уведомлять представление о любых изменениях состояния посредством событий уведомления об изменениях. Свойства и команды, предоставляемые моделью представления, определяют функциональные возможности, предлагаемые пользовательским интерфейсом. В следующем списке приведены характеристики, задачи и обязанности уровня модели представления:
- Он координирует взаимодействие вида с любым классом модели.
- Модель представления и классы модели обычно имеют отношение один ко многим.
- Он может преобразовывать или манипулировать данными модели, чтобы их можно было легко использовать в представлении.
- Он может определять дополнительные свойства, чтобы специально поддерживать представление.
- Он определяет логические состояния, которые представление может использовать для визуального изменения пользовательского интерфейса.
- Он определяет команды и действия, которые пользователь может инициировать.
На следующих шагах мы добавляем два файла в слой модели представления, ViewModelLocator.cs и MainViewModel.cs .
Шаг 1. Добавьте класс MainViewModel
Сначала щелкните правой кнопкой мыши общий проект и выберите « Добавить» , « Новая папка» . Назовите папку ViewModels . Затем щелкните правой кнопкой мыши папку ViewModels и выберите Add , New Item, чтобы добавить класс MainViewModel
.
Измените класс MainViewModel
чтобы он выглядел так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class MainViewModel : ViewModelBase
{
private string _helloWorld;
public string HelloWorld
{
get
{
return _helloWorld;
}
set
{
Set(() => HelloWorld, ref _helloWorld, value);
}
}
public MainViewModel()
{
HelloWorld = IsInDesignMode
?
: «Runs in runtime mode»;
}
}
|
Класс содержит открытое свойство HelloWorld
типа string
. Вы можете добавить дополнительные методы, наблюдаемые свойства и команды в модель представления.
Шаг 2: Добавьте класс ViewModelLocator
Мы добавим открытое свойство для всех моделей представлений в классе ViewModelLocator
и создадим новый ресурс, который мы будем использовать в конструкторе.
Щелкните правой кнопкой мыши папку ViewModels и выберите « Добавить» , « Новый элемент» . Выберите класс и назовите его ViewModelLocator.cs . Обновите класс ViewModelLocator
как показано ниже.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public class ViewModelLocator
{
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
}
|
Класс ViewModelLocator
содержит открытое свойство Main
, метод MainViewModel
которого возвращает экземпляр класса MainViewModel
. Конструктор ViewModelLocator
регистрирует экземпляр SimpleIoc
сервисе SimpleIoc
.
Затем откройте файл App.xaml и добавьте новый ресурс с ViewModelLocator
для использования в конструкторе.
1
2
3
|
<Application.Resources>
<viewModels:ViewModelLocator x:Key=»Locator» />
</Application.Resources>
|
5. Подключение контекста данных
Представление и модель представления могут быть построены и связаны во время выполнения несколькими способами. Самый простой подход — для представления создать экземпляр соответствующей модели представления в XAML. Вы также можете указать в XAML, что модель представления установлена как контекст данных представления.
1
2
3
|
<Page.DataContext>
<vm:MainViewModel/>
</Page.DataContext>
|
Когда страница MainPage.xaml инициализируется, экземпляр MainViewModel
автоматически MainViewModel
и устанавливается как контекст данных представления. Обратите внимание, что модель представления должна иметь конструктор по умолчанию без параметров, чтобы этот подход работал.
Другой подход заключается в том, чтобы программно создать экземпляр модели представления в конструкторе представления и установить его в качестве контекста данных.
1
2
3
4
5
|
public MainPage()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
|
Другой подход заключается в создании экземпляра модели представления и связывании его с его представлением с использованием локатора модели представления. В примере приложения мы используем класс ViewModelLocator
для разрешения модели представления для MainPage.xaml .
1
2
3
|
<Page.DataContext>
<Binding Path=»Main» Source=»{StaticResource Locator}» />
</Page.DataContext>
|
Теперь, когда контекст данных представления установлен в класс MainViewModel
, мы можем получить доступ к его свойствам в представлении. Вы можете привязать текст TextBlock
к свойству HelloWorld
определенному в модели представления.
1
|
<TextBlock Text=»{Binding HelloWorld}» FontSize=»20″ HorizontalAlignment=»Center» VerticalAlignment=»Center»/>
|
6. Служба сообщений
Служба обмена сообщениями в MVVM Light обеспечивает связь между моделями представлений или между моделями представлений и представлениями. Допустим, у вас есть модель представления, которая используется для предоставления бизнес-логики функции поиска, и две модели представления на вашей странице, которые хотят обработать поиск, чтобы показать вывод. Посланник был бы идеальным способом сделать это свободно связанным способом.
Модель представления, которая получает данные поиска, просто отправит «поисковое» сообщение, которое будет использовано любой моделью представления, которая в настоящее время зарегистрирована для использования сообщения. Преимущества использования службы обмена сообщениями:
- простая связь между моделями представлений без необходимости знать друг о друге
- больше потребителей сообщений может быть добавлено без особых усилий
- это упрощает просмотр моделей
Отправить сообщение:
1
|
MessengerInstance.Send(payload, token);
|
Чтобы получить сообщение:
1
2
|
MessengerInstance.Register<PayloadType>(
this, token, payload => SomeAction(payload));
|
В примере приложения мы отправим сообщение из MainViewModel
, которое будет получено MainPage.xaml . Это шаги, необходимые для использования службы сообщений.
Шаг 1: Создайте класс, который будет содержать сообщение для передачи
Создайте новый класс в проекте и назовите его ShowMessageDialog
.
1
2
3
4
|
public class ShowMessageDialog
{
public string Message { get;
}
|
Шаг 2. Определение класса сообщения и широковещательного сообщения.
В MainViewModel.cs создайте экземпляр ShowMessageDialog
и используйте объект Messenger
для передачи сообщения.
1
2
3
4
5
6
|
private object ShowMessage()
{
var msg = new ShowMessageDialog { Message = «Hello World» };
Messenger.Default.Send<ShowMessageDialog>(msg);
return null;
}
|
Это передает сообщение. Нам остается только зарегистрировать получателя и ответить на сообщение.
Шаг 3: Зарегистрируйтесь для получения сообщения и обработки при получении
Откройте MainPage.xaml.cs и зарегистрируйтесь для сообщения в конструкторе.
1
2
3
4
5
6
7
8
9
|
public MainPage()
{
this.InitializeComponent();
Messenger.Default.Register<ShowMessageDialog>
(
this,
(action) => ReceiveMessage(action)
);
}
|
ReceiveMessage
— это метод, который вам нужно реализовать. Он возьмет объект Message
и использует DialogService
для отображения диалогового окна.
1
2
3
4
5
|
private async void ReceiveMessage(ShowMessageDialog action)
{
DialogService dialogService= new DialogService();
await dialogService.ShowMessage(action.Message, «Sample Universal App»);
}
|
Шаг 4: Создать команду для отправки сообщения
Теперь, когда мы можем отправлять и получать сообщения, нам нужно вызвать метод ShowMessage
. MVVM Light обеспечивает поддержку RelayCommand
, которую можно использовать для создания команд в модели представления. Добавьте открытое свойство ShowMessageCommand
в классе MainViewModel
которое вызывает метод ShowMessage
.
1
2
|
private RelayCommand _showMessageCommand;
public RelayCommand ShowMessageCommand => _showMessageCommand ??
|
Затем добавьте Button
в MainPage.xaml и привяжите ShowMessageCommand
к его свойству Command
.
1
|
<Button Command=»{Binding ShowMessageCommand}» Content=»Click Me» HorizontalAlignment=»Center»/>
|
Разверните приложение, чтобы увидеть, все ли работает как положено. Вот снимок того, как MainPage.xaml выглядит в Windows 8.1.
Когда вы нажимаете кнопку Click Me , появляется диалоговое окно.
Messenger — это мощный компонент, который может упростить общение, но также затрудняет отладку кода, поскольку на первый взгляд не всегда ясно, какие объекты получают сообщение.
Вывод
Благодаря реализации шаблона MVVM у нас есть четкое разделение между видом, моделью вида и слоями модели. Как правило, мы пытаемся разработать модель представления так, чтобы она ничего не знала о представлении, которое оно управляет. Это имеет несколько преимуществ:
- Команда разработчиков может работать независимо от команды интерфейса пользователя.
- Модель представления можно легко протестировать, просто вызвав некоторые команды и методы и подтвердив значение свойств.
- В представление можно вносить изменения, не беспокоясь о том, какое влияние это окажет на модель представления и модель.
Не стесняйтесь загружать исходные файлы учебника для использования в качестве справочного материала.