Паттерн Model-View-ViewModel (MVVM) основывается на разделении функциональной части приложения на три ключевых компонента:
View - представление или пользовательский интерфейс
Model - модель или данные, которые используются в приложении
ViewModel - промежуточный слой между представлением и данными, который обеспечивает их взаимодействие
Преимуществом использования данного паттерна является меньшая связанность между компонентами и разделение ответственности между ними. То есть Model отвечает за данные, View отвечает за графический интерфейс, а ViewModel - за логику приложения.
Легкость реализации паттерна MVVM в .NET MAUI и C# стала возможной благодаря встроенному механизму привязки. Как правило, через свойство BindingContext визуального элемента устанавливается объект ViewModel. Далее через этот ViewModel идут все взаимодействия между данными и визуальным интерфейсом.
Рассмотрим простейший пример. Определим класс данных или модели:
public class Person { public string Name { get; set; } = ""; public int Age { get; set; } }
Также добавим в проект класс, который назовем PersonViewModel со следующим содержимым:
using System.ComponentModel; using System.Runtime.CompilerServices; namespace HelloApp; public class PersonViewModel : INotifyPropertyChanged { Person person = new Person{Name="Tom", Age=38}; public event PropertyChangedEventHandler? PropertyChanged; public string Name { get => person.Name; set { if (person.Name != value) { person.Name = value; OnPropertyChanged(); } } } public int Age { get => person.Age; set { if (person.Age != value) { person.Age = value; OnPropertyChanged(); } } } public void OnPropertyChanged([CallerMemberName] string prop = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop)); } }
Это и будет компонент ViewModel, который связывает данные и визуальный интерфейс. По большому счету она представляет обертку над классом Person, определяя все те же свойства. Для упрощения задачи сам объект Person задается непосредственно в классе в качестве глобальной переменной, хотя в реальности там могла бы быть более сложная логика, например, по получению объекта из базы данных, из файла, из сетевого запроса и т.д..
Обычно класс ViewModel реализует интерфейс INotifyPropertyChanged, что позволяет уведомлять систему об изменении его свойств с помощью события
PropertyChanged
.
Теперь создадим визуальную часть. Определим на главной странице MainPage.xaml следующее содержимое:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <VerticalStackLayout Padding="5"> <Label Text="Name" /> <Label Text="{Binding Name}" FontAttributes="Bold" /> <Label Text="Age" /> <Label Text="{Binding Age}" FontAttributes="Bold" /> </VerticalStackLayout> </ContentPage>
Здесь определена привязка к свойствам ViewModel.
А в конструкторе страницы в файле кода MainPage.xaml.cs пропишем в качестве контекста данных для страницы определенную ранее ViewModel:
namespace HelloApp; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); // привязка к ViewModel BindingContext = new PersonViewModel(); } }
И при запуске приложение выведет нам все данные о viewmodel, переданной во view:
При использовании паттерна в качестве представления обычно выступает страница, и, как правило, одно представление (одна страница) связана с одной моделью представления (ViewModel). При этом одну и ту же VıewModel могут использовать несколько представлений.
Стоит отметить, что в этом отношении ViewModel ничего не знает о представлении, что это, какие элементы управления оно содержит. ViewModel только определяет логику обработку без какой-либо связи с графическим интерфейсом.
Для подобным очень простых сценариев вряд ли потребуется определять дополнительную сущность в виде ViewModel, так как проще привязать элементы управления неспосредственно к свойствам объекта Person. Однако на дальней дистанции при развитии приложения это может помочь в более структурной организации логики приложения и упрощении работы по его развитию и поддержке.