Реализация MVVM. ViewModel

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

Для работы с паттерном MVVM создадим новый проект. По умолчанию в проект добавляется стартовое окно MainWindow - это и будет представление. И теперь нам нужна модель и ViewModel.

Добавим в проект новый класс Phone, который и будет представлять модель приложения:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MVVM
{
    public class Phone : INotifyPropertyChanged
    {
        private string title;
        private string company;
        private int price;

        public string Title
        {
            get { return title; }
            set
            {
                title = value;
                OnPropertyChanged("Title");
            }
        }
        public string Company
        {
            get { return company; }
            set
            {
                company = value;
                OnPropertyChanged("Company");
            }
        }
        public int Price
        {
            get { return price; }
            set
            {
                price = value;
                OnPropertyChanged("Price");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string prop = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}

Для уведомления системы об изменениях свойств модель Phone реализует интерфейс INotifyPropertyChanged. Хотя в рамках паттерна MVVM это необязательно. В других конструкциях и ситуациях все может быть определено иначе.

Также добавим в проект новый класс ApplicationViewModel, который будет представлять модель представления:

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.ObjectModel;

namespace MVVM
{
    public class ApplicationViewModel : INotifyPropertyChanged
    {
        private Phone selectedPhone;

        public ObservableCollection<Phone> Phones { get; set; }
        public Phone SelectedPhone
        {
            get { return selectedPhone; }
            set
            {
                selectedPhone = value;
                OnPropertyChanged("SelectedPhone");
            }
        }

        public ApplicationViewModel()
        {
            Phones = new ObservableCollection<Phone>
            {
                new Phone { Title="iPhone 7", Company="Apple", Price=56000 },
                new Phone {Title="Galaxy S7 Edge", Company="Samsung", Price =60000 },
                new Phone {Title="Elite x3", Company="HP", Price=56000 },
                new Phone {Title="Mi5S", Company="Xiaomi", Price=35000 }
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string prop = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}

Это класс модели представления, через который будут связаны модель Phone и представление MainWindow.xaml. В этом классе определен список объектов Phone и свойство, которое указывает на выделенный элемент в этом списке.

В итоге веcь проект будет выглядеть следующим образом:

Применение Model View ViewModel в WPF

Далее изменим код нашего представления - файла MainWindow.xaml:

<Window x:Class="MVVM.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="FontSize" Value="14" />
        </Style>
        <Style TargetType="TextBox">
            <Setter Property="FontSize" Value="14" />
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="0.8*" />
        </Grid.ColumnDefinitions>

        <ListBox Grid.Column="0" ItemsSource="{Binding Phones}"
                 SelectedItem="{Binding SelectedPhone}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5">
                        <TextBlock FontSize="18" Text="{Binding Path=Title}" />
                        <TextBlock Text="{Binding Path=Company}" />
                        <TextBlock Text="{Binding Path=Price}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <StackPanel Grid.Column="1" DataContext="{Binding SelectedPhone}">
            <TextBlock Text="Выбранный элемент"  />
            <TextBlock Text="Модель" />
            <TextBox Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Производитель" />
            <TextBox Text="{Binding Company, UpdateSourceTrigger=PropertyChanged}" />
            <TextBlock Text="Цена" />
            <TextBox Text="{Binding Price, UpdateSourceTrigger=PropertyChanged}" />
        </StackPanel>
    </Grid>
</Window>

Здесь определен элемент ListBox, который привязан к свойству Phones объекта ApplicationViewModel, а также определен набор элементов, которые привязаны к свойствам объекта Phone, выделенного в ListBox.

И изменим файл кода MainWindow.xaml.cs:

using System.Windows;

namespace MVVM
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = new ApplicationViewModel();
        }
    }
}

Здесь достаточно установить контекст данных для данного окна в виде объекта ApplicationViewModel, который свяжет представление и модели Phone.

И если мы запустим приложение, то увидим список объектов. Мы можем выбрать один из них, и его данные появятся в полях справа:

Реализация паттерна MVVM в WPF

При этом не надо определять код загрузки объектов в ListBox, определять обработчики выбора объекта в списке или сохранения его данных. За нас все делает механизм привязки данных.

Определение модели

В данном случае мы сами определяем модель Phone. Однако не всегда мы имеем возможность реализовать в используемой модели интерфейс INotifyPropertyChanged. Также, возможно, мы захотим предусмотреть отдельное представление (отдельное окно) для манипуляций над одной моделью (добавление, изменение, удаление). Подобное представление может иметь в качестве ViewModel объект модели Phone. И в подобных случаях мы можем создать отдельную ViewModel для работы с одним объектом Phone, наподобие:

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MVVM
{
    public class PhoneViewModel : INotifyPropertyChanged
    {
        private Phone phone;

        public PhoneViewModel(Phone p)
        {
            phone = p;
        }

        public string Title
        {
            get { return phone.Title; }
            set
            {
                phone.Title = value;
                OnPropertyChanged("Title");
            }
        }
        public string Company
        {
            get { return phone.Company; }
            set
            {
                phone.Company = value;
                OnPropertyChanged("Company");
            }
        }
        public int Price
        {
            get { return phone.Price; }
            set
            {
                phone.Price = value;
                OnPropertyChanged("Price");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged([CallerMemberName]string prop = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
}
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850