Краткое руководство по MVVM: ключевые моменты и примеры
MVVM (Model-View-ViewModel) — способ организации кода. Он помогает отделить пользовательский интерфейс от логики.
- View содержит только код пользовательского интерфейса. Он отображает экран (текстовые поля, ярлыки, кнопки) и пользовательский ввод. Например, в Windows Forms это обычно Form или Control. В Windows Presentation Foundation (WPF) — это класс Window: файлы XAML и xaml.cs.
- Model — это классы. Это «вещи» в вашей программе. Например, в программе ввода заказов вашими классами моделей могут быть: Customer, Order, InventoryItem. Эти классы будут содержать логику, необходимую для выполнения функций.
- ViewModel используются для связи между View и Model. Они обычно не содержат много логики. Они содержат Model, который должен быть использован во View. Когда человек взаимодействует с пользовательским интерфейсом, ViewModel узнает, какое действие необходимо выполнить, и просит Model сделать это.
Как работает паттерн MVVM?
Как работает паттерн MVVM можно разобрать на примере из реального мира. Представьте, что у нас есть владелец интернет-магазина, веб-мастер и контент-менеджер:
- владелец интернет-магазина (Model) — занимается своей работой, ни на что не отвлекаясь. Если начинается важная акция, он передает веб-мастеру, что нужно добавить новость о ней в блог;
- веб-мастер (ViewModel) – получает информацию от владельца интернет-магазина и передает ее контент-менеджеру;
- контент-менеджер (View) — пишет новость в блог, основываясь на данных, которые предоставил веб-мастер, и публикует ее.
Примеры использования MVVM
Основным примером использования MVVM является программирование графического интерфейса пользователя (GUI). Он используется для простого событийно-управляемого программирования пользовательских интерфейсов путем отделения View от логики бэкенда, управляющей данными.
В WPF View проектируется с помощью языка разметки XAML. Файлы XAML привязываются к ViewModel. Таким образом View отвечает только за представление, а ViewModel — только за управление состоянием приложения.
MVVM очень широко используется в JavaScript-библиотеке Knockout.js.
Реализация паттерна MVVM
Рассмотрим следующую реализацию MVVM с использованием C#, .NET и WPF.
У нас есть класс Model под названием Animals, класс View, реализованный в XAML, и модель ViewModel под названием AnimalViewModel. Обратите внимание, что Model ни о чем не знает, ViewModel знает только о модели, а View знает только о ViewModel.
Событие OnNotifyPropertyChanged-event позволяет обновлять и Model, и View так, что когда вы вводите что-то в текстовое поле во View, Model обновляется. И если что-то обновляет Model, то обновляется и View:
/*Model class*/ public class Animal { public string Name { get; set; } public string Gender { get; set; } } /*ViewModel class*/ public class AnimalViewModel : INotifyPropertyChanged { private Animal _model; public AnimalViewModel() { _model = new Animal {Name = "Cat", Gender = "Male"}; } public string AnimalName { get { return _model.Name; } set { _model.Name = value; OnPropertyChanged("AnimalName"); } } public string AnimalGender { get { return _model.Gender; } set { _model.Gender = value; OnPropertyChanged("AnimalGender"); } } //Event binds view to ViewModel. public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (this.PropertyChanged != null) { var e = new PropertyChangedEventArgs(propertyName); this.PropertyChanged(this, e); } } } <!-- Xaml View --> <Window x:Class="WpfApplication6.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" xmlns:viewModel="clr-namespace:WpfApplication6"> <Window.DataContext> <viewModel:AnimalViewModel/> </Window.DataContext> <StackPanel> <TextBox Text="{Binding AnimalName}" Width="120" /> <TextBox Text="{Binding AnimalGender}" Width="120" /> </StackPanel> </Window>
Изменение кода с помощью MVVM
Давайте посмотрим на код, написанный без использования MVVM. Проблема в том, что единственный способ проверить логику — это вручную запустить программу и ввести значения для каждого сценария:
using System.Linq; using System.Windows; namespace WorkbenchWPF.MVVMPattern.NonPatternVersion { public partial class AccountCreationView : Window { public AccountCreationView() { InitializeComponent(); } private void OnClick_ValidatePassword(object sender, RoutedEventArgs e) { if(txtPassword.Text.Trim().Length < 8) { lblErrorMessage.Text = "Password must be at least eight characters long"; } else if(txtPassword.Text.Trim().Length > 20) { lblErrorMessage.Text = "Password cannot be more than twenty characters long"; } else if(!txtPassword.Text.Any(char.IsUpper)) { lblErrorMessage.Text = "Password must contain at least one upper-case character"; } else if(!txtPassword.Text.Any(char.IsLower)) { lblErrorMessage.Text = "Password must contain at least one lower-case character"; } else if(!txtPassword.Text.Any(char.IsNumber)) { lblErrorMessage.Text = "Password must contain at least one number"; } else { lblErrorMessage.Text = "Password is secure"; } } } }
Теперь обратите внимание на код, написанный с использованием паттерна MVVM. Когда код разделен с помощью MVVM, можно написать автоматизированные тесты, которые могут проверить все возможные значения за считанные минуты:
using System.Windows; using Engine.MVVMPattern.PatternVersion.ViewModels; namespace WorkbenchWPF.MVVMPattern.PatternVersion { public partial class AccountCreationView : Window { private readonly AccountCreationViewModel _viewModel = new AccountCreationViewModel(); public AccountCreationView() { InitializeComponent(); DataContext = _viewModel; } private void OnClick_ValidatePassword(object sender, RoutedEventArgs e) { _viewModel.ValidatePassword(); } } }
Ключевые моменты паттерна MVVM
- Пользователь взаимодействует с View.
- View имеет ссылку на ViewModel, но View Model не имеет информации о View.
- Поддерживается двустороннее связывание данных между View и ViewModel.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: