MVVMパターンとは?

WPF/Silverlightの特徴と一般的な設計原則から導出する
MVVM(Model/View/ViewModel)パターン
わんくま同盟 東京勉強会 #60
尾上 雅則

尾上 雅則(おのうえ まさのり)
◦ 昭和58年度生 フリーランス

使用技術
◦ C#er
◦ WPF/Silverlight・ASP.NET・WindowsFormsなど。
◦ AzureとかASP.NET MVCとか覚えたい。



MVVMer。MVVM星人とか呼ばれたりもします。
Blog : the sea of fertility http://ugaya40.net
Twitter : @ugaya40
WPF/Silverlightの特徴と、
一般的な設計原則から
WPF/Silverlightのための設計パターンである
MVVMパターンを導出して、
MVVMパターンはなんら特別なパターンではない
という事を理解して頂きます。

また、インフラの必要性についても話します。

WPF/Silverlightの考慮すべき特徴の紹介

WPF/Silverlightアプリの設計定石を考える(1)

WPF/Silverlightアプリの設計定石を考える(2)

WPF/Silverlightアプリの設計定石を考える(3)

まとめ
◦ 見た目と機能の分離
◦ 一般的な設計原則から
◦ WPF/Silverlightの特徴から、そしてMVVMパターン
へ
◦ リッチクライアントだから考えなくてはならない事
ControlTemplate
VisualStateManager
双方向データバインド
• DataTemplate
•
•
•

同じコントロールも外観をXAMLだけで別の外見に。
<TreeView>
<ListBox>
画像貼りミス
じゃないんですよ!

外見の変化はカスタムコントロールを作る動機ではなくなった。


コントロールに状態に応じた外観を定義する事が可能
になった。(状態間にアニメーションの定義も可能/状
態を追加する事も可能)
外観に関わるコードはこうやってほぼ全てXAMLに委
譲できる。

WPF/Silverlightのデータバインディングは双方向の
データバインドに対応している

コレクションコントロール(ListBox/TreeView)などに
は最強の武器がある。

WPF/Silverlightでは見た目に関する定義をほとんど
XAMLに委譲できるようになっている。

データバインドが見た目と機能の分離をさらに促進す
る。

データバインドに頼らないで作ろうとすると動作に制
約がつく。
◦ たとえばC#/VBコードから構築されたDataTemplateでは
Templateのすべての機能を使用する事ができない旨がMSDN
に明記されている

http://msdn.microsoft.com/ja-jp/library/ms602715.aspx
一般的な設計原則から
•
レガシーなイベントドリブン
コードの問題点
•
相互依存
•
ざっくりとした一般的なGUI
責務分割型設計

イベントハンドラに全ての処理を書くと、イベントの発
生順序とビジネスドメイン(アプリ本来の問題領域)の処
理が強く結合してしまいやすい。

アプリ本来の処理シーケンスと、見た目のコード
の混在を片づけるには、そりゃあ責務を分離すれ
ば良いんです。
◦ しかし気を付けなければならない事があります。
◦相互依存です。

相互依存とは
◦ 分割された責務が、互いが互いに依存する事。

互いが互いに依存する事で単一責任の原則に反し
やすくなる。

インターフェースによるアプローチ
◦ 相手がインターフェースを実装している事だけを知って
いれば良い。 OOPでの疎結合の基本。

イベントでのObserverパターンによるアプローチ
◦ Observeとは監視するという意味。
◦ イベント受信側について、イベント発行側が全く知る必要がない。

責務間の関連が深い(通信相手の存在が前提)場合
がシンプルなinterfacceの方が良い。
◦ 記録処理クラスと、記録の実体(ファイル・DB)クラスの
通信
◦ いわゆるリポジトリパターン

責務間に関連が無い場合はイベントObserverに
よるアプローチが良い
◦ 完全に責務に関連がない場合、通信相手の存在を前提と
したシンプルなinterfaeよりObserverの方が優秀。

ここまでを踏まえて、GUIアプリをざっくり分け
てみます。
呼出
外観
ビジネスドメイン
(アプリの機能)
イベント通知
ビジネスドメインから外観への通信は
イベントの方が望ましい

ここまでを踏まえて、GUIアプリをざっくり分け
てみます。
呼出
外観
View
ビジネスドメイン
イベント監視
イベント通知
Model

実はこれがMVCに代表されるUIパターンの共通
理念であり、基本的な形。
呼出
View
イベント監視
イベント通知
Model

全てのUIパターンの正しい理解のためには、この
形を理解する事が基本です。あとでも出てくるの
で覚えておいてください。
呼出
View
イベント監視
イベント通知
Model
WPF/Silverlightの特徴から、
そしてMVVMパターンへ
•
コレクションコントロールの罠
•
イベントの発生順序とコントロー
ルの状態の複雑化
•
別途状態ストアを持とう!
•
MVVMパターン

コレクションコントロールには罠がある。
◦ ListBox/ListView

コレクションコントロールには罠がある。
◦ TreeView
展開するまで
やはり子のインスタンス
が無い!


DataTemplate内の別のコントロールの情報をと
りにくい
VisualTreeHelperとかいう静的クラスの、
◦ 自分の子の数を習得するだけのメソッドと
◦ インデックスで対象の子コントロールを取得してくるだ
けのメソッド
◦ でしか、DataTemplate内のコントロールは触る事がで
きない。。。有り得ない。。。

ではどうするか
→ データバインドで全て解決
各項目に対応するような
表示用のデータバインド用オブジェク
トがあれば全てデータバインドで解決
できる
(チェック状態などもboolとして持つ)
むしろ他のアプローチじゃ解決できない!




WPF/Silverlightではコントロールはとことん
データバインド前提で作られている。
コレクションコントロール以外でも、レイアウト
関連プロパティなどでは、イベントの発生状況に
よってプロパティの値が信用できない。
WinForms/ASP.NETまではむしろデータバイン
ドはおまけ機能の印象が強かった。
WPF/Silverlightではデータバインドこそが本流。
使わないと制約だらけ。
◦ コントロールの状態(プロパティ)を、ビジネスド
メイン呼び出しのための状態判断に信用しない方
がよいのが、WPF/Silverlight。
◦ コントロールの状態は、レイアウトシステムとの
連携やコントロールの内部実装で使用する事にな
る。
◦ だから・・・・
コレクションコントロール以外のものも含めて、画
面のレンダリングに必要な動的に変化する情報を保
存する責務を新たに設ける。
バインド用オブジェクト
●
●
テキスト:1992
バインド!
●
●
選択されているかどうか
●
テキスト:1993
●
●
選択されているかどうか
●
●
画面を描画するための状態ストアを別途持ってしま
おう!
外観
画面
XAML
Data
Binding
画面を
レンダリングする
ための状態ストア
つまりこれが・・
呼出
ビジネス
ドメイン
(アプリの機能)
外観
イベント
外観
呼出
Data
Binding
画面
画面を
レンダリングする
ための情報
ビジネス
ドメイン
(アプリの機能)
イベント
View : UIの外観と構造を定義
ViewModel : Viewをレンダリングするための情報
Model : アプリ本来の問題領域に対するコード
呼出
画面
View
Data
Binding レンダリング情報
ビジネス
ドメイン
ViewModel
Model
イベント
この形の事をMVVMパターンと言います。見ての
通り、なんら難しいパターンでも、特別なパターン
でもないのです。
依存
Data
Binding
View
ViewModel
Model
イベント
リッチクライアントだから考えな
ければいけない事
•
•
•
責務間通信に関わる問題
インフラストラクチャの使用
通信手法の統一がもたらすも
の
リッチクライアント開発では、リッチクライアント
だからこそ考えなければならない問題があります。
WinFormsなどの開発で、開発の最後の方まで残り
がちで解決の厄介なバグ、覚えがありませんか?
代表的な一例
そう
メモリリーク
です。
そもそもメモリリークとは
イベント
受信側A
public class イベント受信側A
{
ButtonA.Click += Clicked;
イベント
発行元
ButtonA
private void Clicked(object
sender, RoutedEventArgs e)
{
//処理
Click
イベント公開
そもそもメモリリークとは
イベント
受信側A
public class イベント受信側A
{
実は発行元(Button A)が
ButtonA.Click
+= Clicked;
受信側AのClickedメソッ
ドの参照を保持している
private void Clicked(object
sender, RoutedEventArgs e)
{
//処理
イベント
発行元
ButtonA
Click
イベント公開
そもそもメモリリークとは
イベント
受信側A
public class イベント受信側A
イベントの登録を解除しないで、
{
受信側が勝手に消滅しようとし
ButtonA.Click += Clicked;
ても発行側に参照されているの
で消えられない!
private void Clicked(object
sender, RoutedEventArgs e)
{
//処理
イベント
発行元
ButtonA
Click
イベント公開
つまりメモリリークとは
イベントを公開しているオブジェクトがあり、発行
元より寿命の短いオブジェクトがイベントを受信し
ている時に起きやすい問題。
きちんと登録を解除できれば良いけど、
WPF/Silverlightではそのタイミングの管理が非常
に面倒。
ちなみにWebでは滅多に発生しない問題。
Webではすべてのオブジェクトの生存期間が基本的
に1リクエストの中に納まるから、分けた責務のオ
ブジェクト全てがほぼ同時に生成され、ほぼ同時に
消滅する。(static使用時を除く)
ステートフル(状態を持つ・持ち続ける)アプリ、つ
まりほとんどの場合リッチクライアントに固有の問
題!
MVVMパターンでのメモリリークについて、
それぞれ

View ⇔ ViewModel間

ViewModel ⇔ Model間
◦ コレクションコントロールの中身とか、頻繁にイ
ンスタンスが出来たり消えたりしています。
◦ 検索結果画面など、一時的な画面はWindow消す
時に普通ViewModelも捨てちゃいます。
についてみていきます。
データバインディング機構の正体
Data
Binding
View
ViewModel
データバインディング機構とは
リフレクションなど
View
Data
Binding
イベントによる
変更通知
ViewModel
しかし、データバインディング機構内部では
WeakEventパターン(後述)が適用され、メモリ
リークのリスクがありません。
リフレクションなど
View
ViewModel
イベントによる
変更通知
逆に言えば、データバインディング機構から漏れた
通信手法を使用する事でメモリリークのリスクがあ
ります。
リフレクションなど
View
ViewModel
イベントによる
変更通知
ViewModelとModelの間の通信にはデータバイン
ディング機構などが介在しません。一般的なメモリ
リーク対策を取る事になります。
呼出
ViewModel
Model
イベント通知
そこでWeakEventパターンです。
リフレクションなど
ViewModel
Model
イベント通知
WeakEventパターンとは弱いイベントパターンの
事です。関連クラスはSystem.Windows名前空間
に定義されていて、WPFなどでの使用が考慮され
ているように見えます。
MSDNによれば
http://msdn.microsoft.com/ja-jp/library/aa970850.aspx
弱いイベント パターンは、リスナーをイベントに
登録する必要がある際に、いつ登録を解除するか
を明示的には認識できない場合に使用できます。
ええ、まさにうってつけです。
端的に言えば、イベントを受
ける代理のオブジェクトを立
て、そのオブジェクトをグ
ローバルに弱参照で管理する
事によってCLRにイベントハ
ンドラを参照と認識させない
パターン
端的に言えば、イベントを受
ける代理のオブジェクトを立
いちいち実装とか説明とか
て、そのオブジェクトをグ
やっていられないレベルで
ローバルに弱参照で管理する
面倒なので説明省略
事によってCLRにイベントハ
ンドラを参照と認識させない
パターン
とにかくリッチクライアントは、
ステートフルであるがゆえに
適切に作成するには、ある意味
ではWebより深い知識が要求さ
れます。
要はこんな事を
自分で考えたくないんです!
チームメンバーに全て理
解してもらえますか?
既存の
MVVM補助インフラストラクチャ
を使えば、
そんな事自分で理解する必要も
考える必要もないんです!

Livet
◦ http://ugaya40.net/livet
◦ 作者: 僕
◦ WPF4専用。補助ライブラリとしての機能の他に各種VS用テンプ
レート・スニペット・Expression Blend デザイナ拡張機能など
を持つ。
◦ もうすぐver 1.0

Prism
◦
◦
◦
◦
http://compositewpf.codeplex.com/
作者:MS Pattern & Practiceチーム
WPF3.5/4 Silverlight4用。純粋な補助ライブラリ。
外部の方がテンプレートなどを提供してくれている。チュートリ
アルなどもある。巨大。

MVVM Light Toolkit
◦ http://www.galasoft.ch/mvvm/
◦ 作者:Laurent Bugnion
◦ WPF3.5/4 Silverlight4 WindowsPhone 7用。おそらくは世界
で一番利用者が多いライブラリ。補助ライブラリとしての機能の
他に各種テンプレート・スニペットなどを持つ。

私見では現状ではWPFならLivet一択。
SilverlightならMVVM Light Toolkitでコードビ
ハインドありをおすすめします。Windows
Phone 7 ではMVVM Light Toolkitしか選択肢が
ないのが現状です。

ViewModel⇔Model間通信で提供される機能
◦ MVVM用にカスタマイズされたWeakEventの実装
◦ Livet
 Notificator/ViewModelHelper/NotificationHelper
◦ Prism
 EventAggregator
◦ MVVM Light Toolkit
 Messenger

View⇔ViewModel間通信で提供される機能
◦ 通信手法のデータバインドへの統一
◦ メソッドのバインディング
 DelegateCommand/RelayCommand
◦ XAML機能の拡充
 ビヘイビア・トリガー・アクション
◦ 揮発性の現象への対応
 メッセージングシステム

(補足)View⇔ViewModel間通信
◦ コードビハインド無し云々を聞いた事がある
方もいらっしゃると思いますが、それはView
とViewModel間の通信をデータバインドに統
一する事によって生まれる付随的なメリット
です。それがMVVMパターンの目的であるわ
けではありません。

(補足)View⇔ViewModel間通信
◦ コードビハインドを失くす事で、管理面(責務
の遵守が容易に)、XAMLのXMLたるメリット
(WYSIWYGなエディタとの相性とか)を活か
しやすくなります。
◦ コードビハインドを失くすのが目的ではなく、
データバインドに通信を統一する事で、考慮
事項を減らし、MVVM本来のメリットを引き
出そうとするのが目的!
 外部ライブラリを使うのは敷居が高
い?
それは無い。
スキルが低い人間が混じるからこそ、イ
ンフラが必要。(WeakEventとかみんな
が理解できるもの?)
特別なパターンどころか、
むしろWPF/SLにとって一択ってくらい普通のパターン
外観
画面
呼出
Data
画面を
Binding レンダリングする
ための情報
ビジネス
ドメイン
(アプリの機能)
View
ViewModel
Model
イベント

責務
◦ View:UIの外観と構造を定義
◦ ViewModel :UIレンダリングのためのデータストア
◦ Model : アプリ本来の問題領域を表すコード

責務間の通信
◦ View⇔ViewModel : 極力双方向データバインディン
グで。インフラの導入具合によっては全てデータバイ
ンディングに統一する事も可能。
◦ ViewModel⇔Model : イベントとメソッド呼び出し


各種MVVMインフラが提供する機能は、
WPF/SilverlightでMVVMパターンの持つ思想の
メリットをより引き出したり、面倒な考慮事項
を失くすためのもの。DelegateCommand使う
からMVVMとか、コードビハインド無いから
MVVMとか勘違い。
スキルに自信がないからこそMVVMインフラを
使う。

MVVMで良く聞く具体的な実装要素
(DelegateCommandとか)のうち、何を使えば
どういうメリットがあり、使わなければどんな
メリットが損なわれるかを把握する事で実務で
の導入をしやすくする。
@IT
MVVMパターンの常識
「M」「V」「VM」の役割とは?
http://www.atmarkit.co.jp/fdotnet/chushin/greatblo
gentry_02/greatblogentry_02_01.html

MVC/MVP/PMなどの、別のUIパターンとの違
いを学ぶ。
the sea of fertility
MVVMパターンとイベント駆動開発、そして
MVC/MVP/PMパターンとの関係 - 何故MVVMなのか
http://ugaya40.net/wpf/mvvm-mvc-mvp-pmeventdriven.html

.NET/Silverlight標準、MVVM Light
Toolkit/Prism/Livetなどを採用した場合の何を
どこまで学べば良いかのガイドライン。
the sea of fertility
MVVMパターン学習のファーストステップ - 何をどこま
で勉強するか
http://ugaya40.net/mvvm/mvvm-first.html
以下の方々に
簡易レビュー協力頂きました。
ありがとうございます。
秘密組織 謎クエリの会(3名)
@xin9leさん