MVVMパターンとは、データ(ロジック)とUI機能を分離するデザインパターンの一種で、開発やデバッグを効率的に行えるメリットがある。一方MVVMパターンを導入するが故に構成が複雑になるデメリットである。
WPFはMicrosoftによってMVVMパターンを導入することを目的としたUIフレームワークである。したがって、WPFではMVVMパターンを採用することが多い。ここがMVVMパターンが必要ないWindows Formsと大きく異なる点だが、残念ながらWPFをMVVMパターンで簡潔に説明した書籍がないため初学者には学習しづらい環境になっている。(誰か出版してください)
アプリケーション構造
MVVMパターンは、アプリケーションの構造をView、ViewModel、Modelと3分割する。
View
アプリのユーザーが目で確認できるUI部分つまりデザイン。XAMLで定義する。Windows、テキストボックス、アニメーションなど。Binding実装する必要がある。
Model
データ(ロジック)を処理する部分。例えばデータベースから何かしらのデータを持ってきて計算しその結果を返す機能を持たせたり、組込み機器の制御機能をここに実装する。
Modelは必ずしも必要ではなく、小規模なアプリケーションであればModelの内容をViewModelにコーディングする場合もある。
ViewModel
Viewに表示するデータを渡す部分
ViewとViewModelはDataContextを用い連携する。
InotifyPropertyChangedやINotifyCollectionChangedを実装する必要がある。
MVVMパターンの最小構成
まず話を簡潔にするためにModelがない構成で説明する。1番シンプルな構成で学習する方が概要を掴むのに効率がよい。
View実装
Viewにはbindingを用い実装する
下記コードはTextBlock の表示を実装している。
View(XAML)でbinding宣言
<TextBlock Text="{Binding Path=TextName}"/>
ViewModelの実装
ViewModelではView(XAML)で定義したTextNameをプロパティとして定義
public class ViewModel { public string TextName { get; set; } }
ViewとViewModelの連携
コードビハインドでViewModelのインスタンスを作りDataContextにSetする。
* WPFのコードビハインドは、XAMLと呼ばれるXMLベースのマークアップ言語で作成されたUI要素と、C#で書かれたロジックとを結びつけるためのファイルです。XAMLはUIのデザインや構造を定義し、コードビハインドはそのUI要素に対するイベント処理や動的な振る舞いを定義します。
以下の例ではTextNameに初期値"MVVMパターン"を代入した。
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var vm = new ViewModel(); vm.TextName = "MVVMパターン"; DataContext = vm; } }
Modelの実装
今回は省略
MVVMパターンにInotifyPropertyChangedを実装
ViewModelの実装
前節ではViewのコンストラクタでViewModelのプロパティに変数を代入後、DataContextにViewModelのインスタンスを代入した。これによりViewの変更を行った。
プロパティの変更をDataContext利用時以降もしくはコンストラクタ以外で行う汎用的なアプリケーションにするためには、InotifyPropertyChangedをViewModelに実装する必要がある。
public class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void RaisePropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } private string _textname = "";// 初期値 public string TextName { get { return _textname; } set { if (_textname != value) { _textname = value; RaisePropertyChanged("TextName"); } } } }
ViewとViewModelの連携
プロパティTextNameに値を変更すればViewに変更通知行き表示内容も変わる。
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //ViewModelのクラスからプロパティを設定しUIに反映させる var vm = new ViewModel(); //プロパティの初期値 vm.TextName = "MVVMパターン"; this.DataContext = vm; //プロパティのUpdate vm.TextName = "MVVMパターンその2"; } }