О паттерне MVVM написано достаточно много статей тут и там, а еще здесь. Я постараюсь кратко на простом примере пояснить суть паттерна.
Чем же MVVM особенный?
MVVM очередной вариант классического паттерна MVC, создавался компанией Microsoft специально для WPF. Про отличия MVC, MVP и MVVM можно почитать в этой статье. В MVVM приложение делится на три части: Model, View, View-Model.
Модель (Model) содержит в себе всю логику приложение, при чем модель ничего не знает о том как ее будут использовать. Здесь не должно быть ничего лишнего, особенно это касается событий вроде "Модель изменилась - пора обновить графический интерфейс". В этом случае модель получается до ужаса простой, так как программисту не надо заботиться о дизайнере и наворачивать ненужные конструкции. Более того, модель проще тестировать.
VM (View-Model) прослойка, перегоняющая функционал модели в удобный для представления вид. А так же VM должна оповещать представление о том, что модель изменилась.
Представление (View) - обычный GUI. Тут надо отметить, что представление ничего не знает ни о модели, ни о VM. То есть, представление никак не связано с VM напрямую. То есть получается следующая связь:
Такое возможно только при наличии дусторонних связок, которые бы неявным образом синхронизировали поля у представления и VM. В WPF вкачестве таких связок будут байндинги (binding).
Давайте теперь разберем патерн на простеньком примере.
Надуманный пример.
Сделаем список заметок, который можно редактировать. Добавлять и удалять записи НЕЛЬЗЯ, для этого нужны коммады, о них я расскажу в одном из следующих постов. У заметки будет название (Title) и описание (Description). Итак идем попорядку
Модель
View-Model
Все VM являются наследниками INotifyPropertyChanged. Этот интерфейс необходит для оповещения презентера обо всех изменениях в моделе.
Презентер
Особой красоты наводить не буду
И гланое .cs файл привязанный к разметке
Скриншот
В левой части мы выбираем запись, в правой редактируем, при этом поля изменяются одновременно.
Итог
В разметке xaml нет упонимания ни о моделе, ни о VM, а главную VM мы подсовываем интерфейсу в качестве DataContext. Главное не запутаться в DataContext-ах. В целом мы добились нужной связи.
Исходники лежат здесь.
Чем же MVVM особенный?
MVVM очередной вариант классического паттерна MVC, создавался компанией Microsoft специально для WPF. Про отличия MVC, MVP и MVVM можно почитать в этой статье. В MVVM приложение делится на три части: Model, View, View-Model.
Модель (Model) содержит в себе всю логику приложение, при чем модель ничего не знает о том как ее будут использовать. Здесь не должно быть ничего лишнего, особенно это касается событий вроде "Модель изменилась - пора обновить графический интерфейс". В этом случае модель получается до ужаса простой, так как программисту не надо заботиться о дизайнере и наворачивать ненужные конструкции. Более того, модель проще тестировать.
VM (View-Model) прослойка, перегоняющая функционал модели в удобный для представления вид. А так же VM должна оповещать представление о том, что модель изменилась.
Представление (View) - обычный GUI. Тут надо отметить, что представление ничего не знает ни о модели, ни о VM. То есть, представление никак не связано с VM напрямую. То есть получается следующая связь:
Такое возможно только при наличии дусторонних связок, которые бы неявным образом синхронизировали поля у представления и VM. В WPF вкачестве таких связок будут байндинги (binding).
Давайте теперь разберем патерн на простеньком примере.
Надуманный пример.
Сделаем список заметок, который можно редактировать. Добавлять и удалять записи НЕЛЬЗЯ, для этого нужны коммады, о них я расскажу в одном из следующих постов. У заметки будет название (Title) и описание (Description). Итак идем попорядку
Модель
class NoteModel
{
public String Title { get; set; }
public String Description { get; set; }
public NoteModel(string title = "untitled", string description = null)
{
Title = title;
Description = description;
}
}
Все VM являются наследниками INotifyPropertyChanged. Этот интерфейс необходит для оповещения презентера обо всех изменениях в моделе.
class NotePresenter : INotifyPropertyChanged
{
NoteModel _model;
public string Title
{
get
{
return _model.Title;
}
set
{
_model.Title = value;
OnPropertyChanged("Title");
}
}
public string Description
{
get
{
return _model.Description;
}
set
{
_model.Description = value;
OnPropertyChanged("Description");
}
}
public NotePresenter(NoteModel model)
{
if (model == null) throw new ArgumentNullException("model");
_model = model;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string fieldName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
}
}
#endregion
}
Презентер
Особой красоты наводить не буду
<Window x:Class="Testing_MVVM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Testing MVVM" Height="350" Width="525"
>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
Grid.ColumnDefinitions>
<ListBox Grid.Column="0" ItemsSource="{Binding Notes}" x:Name="ListOfNotes">
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="5" BorderBrush="Blue" Margin="5">
<StackPanel>
<TextBlock Text="{Binding Title}"/>
<TextBlock Text="{Binding Description}"/>
StackPanel>
Border>
DataTemplate>
ListBox.ItemTemplate>
ListBox>
<ContentControl Grid.Column="1" Content="{Binding ElementName=ListOfNotes, Path=SelectedValue}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ContentControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" MinWidth="100"/>
Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Title"
VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1"
Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Description"
VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1"
Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"/>
Grid>
DataTemplate>
ContentControl.ContentTemplate>
ContentControl>
Grid>
Window>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
//по хорошему презентер должен создаваться и устанавливаться в другом месте
//или передаваться в конструктор
DataContext = new NotesListPresenter(
new NoteModel("Утро", "Еле встал"),
new NoteModel("Обед", "отлично поел"),
new NoteModel("Вечер", "Смотрел футбол"),
new NoteModel("Ночь", "Сладко-сладко поспал"));
}
}
Скриншот
В левой части мы выбираем запись, в правой редактируем, при этом поля изменяются одновременно.
Итог
В разметке xaml нет упонимания ни о моделе, ни о VM, а главную VM мы подсовываем интерфейсу в качестве DataContext. Главное не запутаться в DataContext-ах. В целом мы добились нужной связи.
Исходники лежат здесь.
Комментариев нет:
Отправить комментарий