Паттерн Model-View-ViewModel

Последнее обновление: 29.01.2023

Паттерн Model-View-ViewModel (MVVM) основывается на разделении функциональной части приложения на три ключевых компонента:

  • View - представление или пользовательский интерфейс

  • Model - модель или данные, которые используются в приложении

  • ViewModel - модель представления - промежуточный слой между представлением и данными, который обеспечивает их взаимодействие

Преимуществом использования данного паттерна является меньшая связанность между компонентами и разделение ответственности между ними. То есть Model отвечает за данные, View отвечает за графический интерфейс, а ViewModel - за логику приложения.

Наличие механизма привязки облегчает реализацию этого паттерна в Windows Forms.

Например, пусть у нас данные представлены следующим типом Person:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public int Age { get; set; }
    public override string ToString() => Name;
}

Данный класс представляет человека и имеет три свойства для хранения идентификатора, имени и возраста.

Определим класс модели представления ViewModel, который будет называться MainViewModel и будет иметь следующий код:

public class MainViewModel
{
    // выбранный объект Person для отображения
    public Person? SelectedPerson { get => People.FirstOrDefault(p => p.Id == SelectedId); }
    // id выбранного объекта
    public int SelectedId { get; set; }
    // данные для отображения в списке
    public List<Person> People { get; }
    public MainViewModel()
    {
        People = new()
        {
            new Person {Id=1, Name="Tom", Age=38 },
            new Person {Id=2, Name ="Bob", Age = 42},
            new Person {Id=3, Name = "Sam", Age = 25}
        };
        SelectedId = 2; // пусть по умолчанию выбран 2-й объект
    }
}

Модель представления хранит данные для отображения - список People, который по умолчанию содержит 3 объекта Person.

Кроме того, определено свойство SelectedId - идентификатор выбранного объекта.

Для отображения выбранного объекта также определено свойство SelectedPerson, которое возвращает объект Person из списка People по выбранному Id.

Теперь создадим представление - определим следующую форму:

namespace MetanitApp;

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        
        // ListBox для отображения списка People
        ListBox peopleListBox= new ListBox();
        peopleListBox.Dock= DockStyle.Fill;
        peopleListBox.SelectionMode = SelectionMode.One;
        Controls.Add(peopleListBox);

        // метка для отображения выбранного элемента
        Label selectedPersonLabel = new Label();
        selectedPersonLabel.Margin = new Padding(20);
        selectedPersonLabel.Font = new Font(FontFamily.GenericSansSerif, 12);
        selectedPersonLabel.Dock = DockStyle.Top;
        Controls.Add(selectedPersonLabel);

        // в качестве констеста данных форма использует ViewModel
        DataContext = new MainViewModel();

        // привязка свойства DataSource в ListBox к свойству People в MainViewModel
        peopleListBox.DataBindings.Add(new Binding("DataSource", DataContext, "People", false, DataSourceUpdateMode.OnPropertyChanged));
        peopleListBox.DisplayMember = "Name";
        peopleListBox.ValueMember= "Id";
        // привязка свойства SelectedValue в ListBox к свойству SelectedId в MainViewModel
        peopleListBox.DataBindings.Add(new Binding("SelectedValue", DataContext, "SelectedId", false, DataSourceUpdateMode.OnPropertyChanged));
        // привязка свойства Text в Label к свойству SelectedPerson в MainViewModel
        selectedPersonLabel.DataBindings.Add(new Binding("Text", DataContext, "SelectedPerson", false, DataSourceUpdateMode.OnPropertyChanged,""));
    }
}

Здесь в качестве контекста данных для формы и всех вложенных элементов устанавливается MainViewModel:

DataContext = new MainViewModel();

Далее мы можем установить привязки свойств элементов ListBox и Label к свойствам модели представления. Так, свойство DataSource в ListBox привязано к свойству People в MainViewModel:

peopleListBox.DataBindings.Add(new Binding("DataSource", DataContext, "People", false, DataSourceUpdateMode.OnPropertyChanged));

Поскольку в качестве свойства значения в ListBox применяется свойство Id объекта Person

peopleListBox.ValueMember= "Id";

то с помощью свойства SelectedValue можно получить идентификатор выбранного элемента. И в данном случае мы устанавливаем привязку к свойству SelectedId в MainViewModel:

peopleListBox.DataBindings.Add(new Binding("SelectedValue", DataContext, "SelectedId", false, DataSourceUpdateMode.OnPropertyChanged));

В конце для отслеживания выбранного элемента устанавливаем привязку свойства Text у элемента Label к свойству SelectedPerson модели представления. Причем поскольку у нас потенциально может быть ситуация, когда не будет выбран объект, то есть он будет равен null, то с помощью шестого параметра конструктора Binding задаем значение по умолчанию на этот случай - здесь это пустая строка:

selectedPersonLabel.DataBindings.Add(new Binding("Text", DataContext, "SelectedPerson", false, DataSourceUpdateMode.OnPropertyChanged,""));

В итоге ListBox отобразит список объектов, а метка Label - выбранный объект:

Model View ViewModel в Windows Forms и C#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850