← Все вопросы

Что такое паттерн MVVM в C# и зачем он нужен в WPF?

Задан 15 месяцев назад1.1к просмотров2 ответа
12

Все WPF-проекты пишут на MVVM. Я понимаю буквы (Model-View-ViewModel), но не понимаю, что куда класть и зачем эта сложность вместо обычного кода в обработчиках кнопок. Объясните паттерн MVVM на простом примере.

2 ответа

18
✓ Принятый ответ — помог автору

MVVM (Model-View-ViewModel) — архитектурный паттерн, который разделяет приложение на три слоя:

  • Model — данные и бизнес-логика (классы сущностей, работа с БД, API);
  • View — интерфейс (XAML-разметка, без логики);
  • ViewModel — посредник: хранит состояние для View, команды, и общается с Model.

Связь View ↔ ViewModel идёт через Binding, а не через прямые вызовы. View не знает о ViewModel напрямую — она просто привязана к её свойствам.

Пример. ViewModel:

public class MainViewModel : INotifyPropertyChanged
{
    private string _name = "";
    public string Name
    {
        get => _name;
        set { _name = value; OnPropertyChanged(); }
    }

    public string Greeting => string.IsNullOrEmpty(Name)
        ? "Введите имя"
        : $"Привет, {Name}!";

    public event PropertyChangedEventHandler? PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string? prop = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
        if (prop == nameof(Name)) OnPropertyChanged(nameof(Greeting));
    }
}

View (XAML) привязывается к ViewModel:

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>
<StackPanel Margin="10">
    <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBlock Text="{Binding Greeting}" FontSize="20"/>
</StackPanel>

Зачем это нужно:

  1. Тестируемость — ViewModel это обычный C#-класс без UI, его легко покрыть юнит-тестами;
  2. Разделение труда — дизайнер правит XAML, программист — ViewModel;
  3. Чистота — нет «спагетти» из обработчиков, где логика прибита к кнопкам;
  4. Переиспользование — одну ViewModel можно показать в разных View.

Да, для крошечной утилиты MVVM избыточен. Но на проекте от пары экранов он быстро окупается. Для команд (вместо кликов в код-бихайнде) используют ICommand / RelayCommand.

7

Дополню про команды, без которых MVVM не полон. Чтобы кнопка не вызывала обработчик в код-бихайнде, а дёргала метод ViewModel, используют ICommand:

public class RelayCommand : ICommand
{
    private readonly Action _execute;
    private readonly Func<bool>? _canExecute;
    public RelayCommand(Action execute, Func<bool>? canExecute = null)
    { _execute = execute; _canExecute = canExecute; }
    public bool CanExecute(object? p) => _canExecute?.Invoke() ?? true;
    public void Execute(object? p) => _execute();
    public event EventHandler? CanExecuteChanged;
}

И привязка в XAML:

<Button Content="Сохранить" Command="{Binding SaveCommand}"/>

Так во View вообще не остаётся Click-обработчиков — вся логика в ViewModel. На практике берут готовый RelayCommand из библиотек вроде CommunityToolkit.Mvvm и не пишут руками.

Ваш ответ

Войдите, чтобы ответить на вопрос.
Поддержать проект