Сводная информация о Главе 18. MVVM
Примечание.
Эта книга была опубликована весной 2016 года и с тех пор не обновлялась. Многое в этой книге остается ценным, но некоторые материалы устарели, а некоторые разделы перестали быть полностью верными или полными.
Одним из лучших подходов к разработке приложения является отделение пользовательского интерфейса от базового кода, который иногда называют бизнес-логикой. Для этого существует несколько способов, но один из них специально разработан для сред на основе XAML и известен как "Модель — представление — модель представления" или MVVM.
Взаимосвязи в MVVM
Приложение MVVM имеет три уровня.
- Модель предоставляет базовые данные, иногда через файлы или веб-доступ.
- Представление выполняет роль пользовательского интерфейса или уровня представления, и обычно реализуется в XAML.
- Модель представления (ViewModel) соединяет Модель с Представлением.
Модель ничего не знает о ViewModel, а ViewModel — о Представлении. Эти три уровня обычно взаимодействуют друг с другом по следующим механизмам?
Во многих небольших программах (а иногда даже в больших) Модель может отсутствовать или быть полностью встроенной во ViewModel.
ViewModel и привязка данных
Чтобы участвовать в привязке данных, ViewModel должна уметь информировать Представление об изменении свойств ViewModel. Для этого ViewModel реализует интерфейс INotifyPropertyChanged
в пространстве имен System.ComponentModel
. Это относится скорее к .NET, чем к Xamarin.Forms. (Обычно ViewModel пытается остаться независимой от платформы.)
Интерфейс INotifyPropertyChanged
объявляет одно событие с именем PropertyChanged
, которое сигнализирует об изменении свойства.
Часы ViewModel
DateTimeViewModel
из библиотеки Xamarin.FormsBook.Toolkit определяет свойство типа DateTime
, значение которого изменятся по таймеру. Этот класс реализует INotifyPropertyChanged
и активирует событие PropertyChanged
при каждом изменении свойства DateTime
.
Пример MvvmClock создает экземпляр этой ViewModel и использует привязку данных к ViewModel для отображения сведений о текущих дате и времени.
Интерактивные свойства во ViewModel
Свойства ViewModel могут быть более интерактивными, как показано в классе SimpleMultiplierViewModel
, который входит в пример SimpleMultiplier. Привязки данных предоставляют значения множителей из двух элементов Slider
и отображают произведение с помощью Label
. При этом вы можете вносить достаточно существенные изменения в этот интерфейс через XAML, не вызывая никаких изменений во ViewModel или файле кода программной части.
ViewModel для цвета
ColorViewModel
из библиотеки Xamarin.FormsBook.Toolkit включает в себя цветовые модели RGB и HSL. Его использование представлено в примере HslSliders:
Упрощение ViewModel
Вы можете упростить код ViewModel, определив метод OnPropertyChanged
с атрибутом CallerMemberName
, который автоматически получает имя вызывающего свойства. Класс ViewModelBase
из библиотеки Xamarin.FormsBook.Toolkit выполняет именно эту функцию и служит базовым классом для ViewModel.
Командный интерфейс
MVVM работает с привязками данных, а они в свою очередь — со свойствами, поэтому возможности MVVM довольно ограничены при обработке события Clicked
из Button
или события Tapped
из TapGestureRecognizer
. Чтобы ViewModel могла обрабатывать такие события, Xamarin.Forms поддерживает командный интерфейс.
Командный интерфейс объявляет себя в Button
с двумя открытыми свойствами:
Command
с типомICommand
(определено в пространстве именSystem.Windows.Input
);CommandParameter
типаObject
Чтобы поддерживать командный интерфейс, во ViewModel нужно определить свойство с типом ICommand
и выполнить для него привязку данных к свойству Command
из Button
. Интерфейс ICommand
объявляет два метода и одно событие:
- метод
Execute
с аргументом типаobject
; - метод
CanExecute
с аргументом типаobject
, который возвращаетbool
; - событие
CanExecuteChanged
.
Внутри ViewModel присваивает каждому свойству с типом ICommand
значение экземпляра класса, который реализует интерфейс ICommand
. Через привязку данных Button
изначально вызывает метод CanExecute
и отключается, если этот метод возвращает false
. Также она назначает обработчик для события CanExecuteChanged
и вызывает CanExecute
при активации этого события. Если включен Button
, он вызывает метод Execute
при каждом нажатии Button
.
Возможно, у вас уже есть существующие ViewModels, созданные раньше Xamarin.Forms, и они даже могут поддерживать командный интерфейс. Для новых ViewModels, которые будут использоваться только с Xamarin.Forms, Xamarin.Forms предоставляет класс Command
и класс Command<T>
, который реализует интерфейс ICommand
. Для аргументов методов Execute
и CanExecute
используется универсальный тип.
Простое выполнение метода
Пример PowersOfThree демонстрирует применение командного интерфейса из ViewModel. Класс PowersViewModel
определяет два свойства с типом ICommand
, а также два частных свойства, которые он передает в простейший конструктор Command
. Эта программа содержит привязки данных из ViewModel к свойствам Command
двух элементов Button
.
Элементы Button
можно свободно заменить в XAML объектами TapGestureRecognizer
, не меняя код.
Калькулятор, ну почти
Пример AddingMachine использует оба метода класса ICommand
: Execute
и CanExecute
. Он использует также класс AdderViewModel
из библиотеки Xamarin.FormsBook.Toolkit. ViewModel содержит шесть свойств с типом ICommand
. Они инициализируются из конструктора Command
и конструктора Command
класса Command
, а также конструктора Command<T>
класса Command<T>
. Все числовые кнопки на сумматоре привязаны к свойству, которое инициализируется значением Command<T>
, а аргумент string
— к Execute
, где CanExecute
обозначает конкретную кнопку.
ViewModel и жизненный цикл приложения
AdderViewModel
из примера AddingMachine определяет также два метода с именами SaveState
и RestoreState
. Эти методы вызываются из приложения, когда оно переходит в спящий режим и пробуждается из спящего режима.