Что нового
  • Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Реализация Паттерна Mvvm На Примере C# (wpf). «нестрогий» Вариант

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,071
Баллы
155
Возраст
51
Model-View-ViewModel (MVVM) – архитектурный паттерн, ориентированный главным образом на платформы, поддерживающие связывание данных и элементов пользовательского интерфейса (например, WPF).

MVVM сравнительно «молодой» паттерн (впервые представлен Джоном Госсманом в 2005 году [1]).


Описание паттерна MVVM


MVVM преследует те же цели, что и MVC. Разделить бизнес-логику и пользовательский интерфейс. Однако в MVC изменения, производимые пользователем при работе с интерфейсом, не влияют непосредственно на модель, а предварительно обрабатываются Контроллером. В MVVM происходит двустороннее связывание.

Различие между этими паттернами лучше можно схематично представить следующими диаграммами.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


Паттерн MVVM





Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


Паттерн MVC


Паттерн MVVM состоит из следующих компонентов:

  • Модель (англ. Model)
    Представляет собой бизнес-логику приложения;
  • Представление (англ. View)
    Графический интерфейс для работы с данными или их отображения (окна, кнопки, таблицы и т.д.);
  • Модель представления (англ. ViewModel)
    Обёртка подлежащих связыванию данных из модели, которая содержит методы, которые используются представлением для работы с моделью.

Применительно к WPF, окно приложения, это представление (всегда). Остальные компоненты паттерна принято реализовывать в виде не визуальных классов. Подробнее реализация MVVM в WPF будет рассмотрена далее на прикладном примере.

Пример реализации


Допустим, нам необходимо реализовать каталог автомобилей, который содержит информацию о моделях автомобилей, их максимальной скорости и стоимости.

Модель


Создадим класс, который описывает автомобиль и будет являться моделью в нашем приложении.

Для обеспечения возможности связывания требуется, чтобы можно было отслеживать изменения в модели. Поэтому её класс должен реализовывать интерфейс INotifyPropertyChanged (пространство имён System.ComponentModel).

Ниже приведён код этого класса:

class Car : INotifyPropertyChanged
{
private string _model;
private int _maxSpeed;
private decimal _price;
public string Model
{
get { return _model; }
set
{
_model = value;
OnPropertyChanged("Model");
}
}
public int MaxSpeed
{
get
{
return _maxSpeed;
}
set
{
_maxSpeed = value;
OnPropertyChanged("MaxSpeed");
}
}
public decimal Price
{
get { return _price; }
set
{
_price = value;
OnPropertyChanged("Price");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}

Если не считать требования по реализации интерфейса INotifyPropertyChanged, то, как и в большинстве случаев, данная модель представляет собой обычный «сущностный» класс.

Модель представления


Модель представления является по сути посредником между представлением и моделью. Для поддержки связывания модель представления также должна реализовывать интерфейс INotifyPropertyChanged.

В классе модели представления создадим закрытое поле и свойство для работы с выбранным из каталога автомобилем.

private Car _selectedCar;
public Car SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value;
OnPropertyChanged("SelectedCar");
}
}

Сам каталог будет представлен в виде коллекции, которую для простоты будем заполнять в конструкторе.

public ObservableCollection<Car> Cars { get; set; }
public CarViewModel()
{
Cars = new ObservableCollection<Car>
{
new Car { Model="ВАЗ-2105", MaxSpeed=150, Price=56000 },
new Car { Model="LADA Priora", MaxSpeed=170, Price=560000 },
new Car { Model="КамАЗ", MaxSpeed=100, Price=5600000 }
};
}

Также включим в модель представления два метода. Для добавления нового автомобиля и удаления уже существующего.

public void AddCar()
{
Car car = new Car();
Cars.Insert(0, car);
SelectedCar = car;
}
public void DeleteCar()
{
if (_selectedCar != null)
{
Cars.Remove(SelectedCar);
}
}

Методов для редактирования не добавляем так как необходимый функционал полностью обеспечивается за счёт связывания.

«Строгий» и «нестрогий» варианты реализации

При строгом следовании паттерну MVVM, добавление и удаление также должны быть реализованы через связывание с помощью механизма команд. Это практически полностью избавляет представление о программные логики, но сильно усложняет и без того не простую архитектуру. Поэтому, в статье рассмотрен несколько упрощённый («нестрогий») вариант реализации.

Ниже приведён полный исходный код класса модели представления.

class CarViewModel : INotifyPropertyChanged

{
private Car _selectedCar;
public ObservableCollection<Car> Cars { get; set; }
public Car SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value;
OnPropertyChanged("SelectedCar");
}
}
public CarViewModel()
{
Cars = new ObservableCollection<Car>
{
new Car { Model="ВАЗ-2105", MaxSpeed=150, Price=56000 },
new Car { Model="LADA Priora", MaxSpeed=170, Price=560000 },
new Car { Model="КамАЗ", MaxSpeed=100, Price=5600000 }
};
}
public void AddCar()
{
Car car = new Car();
Cars.Insert(0, car);
SelectedCar = car;
}
public void DeleteCar()
{
if (_selectedCar != null)
{
Cars.Remove(SelectedCar);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}


Представление


Как уже говорилось ранее, в случае WPF представление, это окно приложения.

«Строгий» и «нестрогий» варианты реализации

При «строгой» реализации в коде окна присутствует только инициализация модели представления в конструкторе.

public MainWindow()
{
InitializeComponent();
DataContext = new CarViewModel();
}

При «нестрогой» добавляются методы событийной модели для работы с данными. В данном случае это обработчики кликов для кнопок добавления и удаления автомобилей соответственно.

private void Add_Click(object sender, RoutedEventArgs e)
{
((CarViewModel)DataContext).AddCar();
}
private void Delete_Click(object sender, RoutedEventArgs e)
{
((CarViewModel)DataContext).DeleteCar();
}


Связывание конкретный элементов управления с данными осуществляется в XAML.

Сам механизм связывания мы подробно рассматривать не будем. Также, как и механизм команд, это тема для отдельной статьи. Приведём лишь пример разметки, которая отображает каталог автомобилей в ListBox, а информацию о выбранном автомобиле (выбранный мышью элемент в ListBox).

<Window x:Class="MVVM_Example.MainWindow"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:d=http://schemas.microsoft.com/expression/blend/2008
xmlns:mc=http://schemas.openxmlformats.org/markup-compatibility/2006
xmlns:local="clr-namespace:MVVM_Example"
mc:Ignorable="d"
Title="MVVM_Example" Height="403.921" Width="310.294">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" DataContext="{Binding SelectedCar}" Grid.ColumnSpan="2">
<TextBlock Text="Выбранный элемент" Margin="0,0,-233,0" />
<TextBlock Text="Модель" />
<TextBox Text="{Binding Model, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="Максимальная скрорость, км/ч" />
<TextBox Text="{Binding MaxSpeed, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="Цена, руб." />
<TextBox Text="{Binding Price, UpdateSourceTrigger=PropertyChanged}" />
<Button Click="Add_Click">+</Button>
<Button Click="Delete_Click" >-</Button>
</StackPanel>
<ListBox Grid.Column="0" Grid.Row="0" ItemsSource="{Binding Cars}"
SelectedItem="{Binding SelectedCar}" Grid.ColumnSpan="2" Margin="0,170,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5">
<TextBlock FontSize="18" Text="{Binding Path=Model}" />
<TextBlock Text="{Binding Path=MaxSpeed}" />
<TextBlock Text="{Binding Path=Price}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

На скриншоте показана работа программы, которая была написана в качестве примера для данной статьи.


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Резюме


Паттерн MVVM хорошо подходит для десктоп приложений на платформах поддерживающих связывание и которые имеют сложную бизнес-логику.

Он позволяет добиться значительно большей гибкости, расширяемости и в немалой степени облегчает сам процесс разработки. Так же, как и в MVC в MVVM для модели и модели представления можно применять такие паттерны, как супертип слоя, отложенная инициализация, фабрика и др. Кроме того, применяя MVVM можно практически полностью разделить работу дизайнера и программиста.

Но, всё это хорошо для достаточно сложных проектов на соответствующих платформах.

Для простых программ MVVM (также, как и MVC) создаёт лишь ничем неоправданные сложности. А, если платформа не поддерживает связывание (например, Windows Forms), то сама реализация паттерна MVVM усложняется на порядок и в этом случае гораздо эффективнее использовать другие паттерны, которым связывание не требуется.

Источники


  1. Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    (Википедия)

  2. Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

    (Википедия)
 
Вверх