MVVM
Model-View-ViewModelの略です。
WPFがどうしてもこれに沿わないといけない、という決まりはないんですが、この考えに沿うとアプリが作りやすくなります。
MVCアーキテクチャとほとんど変わらない概念なのですが、もう一回復習ついでに書きます。
MVVMの基本
MVCとかMVVMとかの基本はアプリケーションの役割を以下の3つに分けることです。
無論、オブジェクト指向がベースです。
オブジェクト指向がベースなので、Modelはデータそのものというよりはその器を作るイメージがかなり大きいです。
- Model:データの形を決めるためのクラス。どんなデータをどういった形でまとめるのか、をオブジェクトを意識してまとめるといい感じにまとまります。
- View:GUIの一番表面的なモノ。WPFではXAMLが基本で、どの画面にどのパーツ(WPFではコントロールと言ったりする)を配置するかを書きます。極力それ以外は書かないようにします。
-
ViewModel:その名の通りViewとModelをつなげるためのクラス。ここには、Viewに載せるフィールドのプロパティを用意することがWPFでは求められます。
Example
なんかよくわからない気がするので簡単なWPFアプリを作ってみようと思います。
仕様
レモンおじさんはPなので、765,346,シアターの3つの事務所にそれぞれいるアイドルを管理するアプリを作りたいと思いました。
とりあえずはリストに事務所の名前とアイドルの名前を羅列させるアプリを作ります。
WPFアプリケーションを新規作成
Visual StudioでWPFアプリを新規作成するとまずはViewのデザイナが出てきます。
上がデザイナで下がそれに従っているXAMLです。
たぶん下のようなXAMLが書かれていると思います。
このまま何も考えずに実行ボタンをクリックするとウィンドウが立ち上がります。
xボタンを押すとウィンドウが消え、実行が終了します。
<Window x:Class="IdolApplication.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:IdolApplication" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </Window>
XAML解説
Windowはその名の通り、このWindowの情報です。xmlns=hogehogeと書いてあるのは、このXAMLはWPFで使っているということを示すためのお約束です。
覚えておかないといけないのは以下3つ。
<Window x:Class="IdolApplication.MainWindow" xmlns:local="clr-namespace:IdolApplication" Title="MainWindow" Height="350" Width="525">
1行目はこのWindowを管理するためのクラス名。実はこのXAMLの裏にMainWindow.xaml.csというC#コードが潜んでおり、それがインスタンスを生成しています。
XAMLに書けないView処理はここに書いていきます。「Viewのビハインド」とかって言うそうです。
2行目は名前空間の変数。これが以外に重要で、デフォルトではlocalにView自身の名前空間が割り当てられています。これは主にViewModelがどれかを指定するときに使います。
3行目はWindowのプロパティですね。単純にタイトルバーに表示するタイトルと高さと幅です。
いきなりViewを作ってもしかたがないのでとりあえずはModelを作りましょう。
Model
今回はアイドルのオブジェクトを作ってそこに所属事務所のフィールドがあればよさそうです。
さくっと、クラスを以下のように作ってみましょう。
namespace IdolApplication { public class Idol { public string Name { get; set; } public string Office { get; set; } public Idol(string _name, string _office) { this.Name = _name; this.Office = _office; } } }
WPFでは外に公開したいデータは必ずプロパティを用意しましょう。
プロパティでなければ、たとえpublicなフィールドであってもデータを取ってこようとしないでめんどくさいことになります。
C#でプロパティを定義するのは簡単なので外からアクセスしてほしいフィールドはプロパティにする癖をつけましょう。
ViewModel
いわゆるコントローラです。
また、実際にViewに表示させるデータをこのクラスに持たせます。
今回はIdolのリストを単純に作るだけで良いわけなので作ってしまいます。
using System.Collections.ObjectModel; namespace IdolApplication { class MainWindowViewModel { public ObservableCollection<Idol> Idols { get; set; } public MainWindowViewModel() { Idols = new ObservableCollection<Idol> { new Idol("Haruka", "765"), new Idol("Chihaya", "765"), new Idol("Miki", "765"), new Idol("Uduki", "346"), new Idol("Rin","346"), new Idol("Mio","346"), new Idol("Mirai","シアター"), new Idol("Udon","シアター"), new Idol("Tsubasa","シアター") }; } } }
上のようなコードですね。
Idolsにたくさんアイドルが勧誘できました。
めんどくさいのでコンストラクタで代入をしてますが、本来はXMLやJSON、データベースからデータを取ってくるイメージです。
その際は、DB用のModelクラスを一つ作ってそのクラスのインスタンスをViewModelで作ると楽になる気がします。
また、ObservableCollectionというのは、要はListですがデータバインディングを行うときに使うと便利なリストです。
Listを継承しているので、Listと同じように使うことができます。
それはおいおい説明するとして、今のところはListだと考えましょう。
View
さて、データの準備はできたのであとは表示するだけです。
今回はDataGridというコントロールを使って表示します。
まずはコードです。
<Window x:Class="IdolApplication.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:IdolApplication" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <local:MainWindowViewModel x:Name="ViewModel" /> </Window.DataContext> <Grid> <DataGrid Name="IdolDataGrid" ItemsSource="{Binding Path=Idols}"> <DataGrid.Columns /> </DataGrid> </Grid> </Window>
ここが一番めんどくさいところですね…
一個一個メモ。
Window.DataContext
<Window.DataContext> <local:MainWindowViewModel x:Name="ViewModel" /> </Window.DataContext>
本来、Viewは何も記述をしなければViewのDataContextというオブジェクトを参照しに行きます。
ただ、Viewの中にデータの情報を記述するのはMVVM的にあまりよろしくないので<local:〜の部分でDataContextの更新を行っています。
基本的にはここにはViewModelを記述して、ViewModelのプロパティを読み込んでもらうようにします。
表記法としては名前空間:クラス名みたいな感じです。
あとはお好みで名前を、と言った感じです。xはWindow.DataContextで使えるやつを提供してくれる名前空間だと思います。
Grid、DataGrid
<Grid> <DataGrid Name="IdolDataGrid" ItemsSource="{Binding Path=Idols}"> <DataGrid.Columns /> </DataGrid> </Grid>
Windows.DataContext以下は実際のViewです。
Gridというのは、ウィンドウ上の領域のことでこの中に色々なコントロールを埋め込めます。
今回はこの中にHTMLのようにDataGridというコントロールを埋め込んでいます。
重要なのは、
<DataGrid Name="IdolDataGrid" ItemsSource="{Binding Path=Idols}">
のItemsSourceという部分で、ここでWindow.DataContextで指定したクラスのどのコレクションをソースにするかを指定します。
この指定のことをWPFではバインディングというので、Bindingほげほげとか書いてます。
また、Bindingされたプロパティはユーザの操作によって中身が書き換わるとViewModel内にあるプロパティも連動して中身が書き換わります。
その逆もしかりでViewModelで変化が起きたバインディングされたプロパティはViewにその結果が反映されます(正確には一工夫必要)。
これをデータバインディングと呼び、WPFを用いる利点の一つとなっています。
結果
さて、最終的にはこんなのが表示されれば成功です。
以上、MVVMと簡単なWPFアプリの作り方でした。
おしまい。