[解決済み] MVVMテンプレートの好例
質問
現在、Microsoft MVVM テンプレートを使用していますが、詳細な例がないことに不満を感じています。 付属のContactBookの例では、Commandの処理はほとんど見られず、私が見つけた唯一の例はMSDN Magazineの記事で、コンセプトは似ていますが、少し異なるアプローチを使用しており、依然として複雑さに欠けています。 少なくとも基本的なCRUD操作とダイアログ/コンテンツ切り替えを示す、まともなMVVMの例はないのでしょうか?
皆さんの提案が本当に役に立ったので、良いリソースのリストを作り始めます
フレームワーク/テンプレート
お役立ち記事
- Model-View-ViewModel デザインパターンによるWPFアプリケーション
- .NET 3.5におけるデータバリデーション
- ViewModel を使用して意味のある検証エラーメッセージを提供する
- アクションベースの ViewModel とモデルの検証
- ダイアログ
- MVVMにおけるコマンドバインディング
- WPFのためのMVCだけではありません
- MVVM + Mediatorの例 応用編
スクリーンキャスト
その他のライブラリ
- WPF Disciplesの改良型Mediator Patternの実装。 (より複雑なナビゲーションを行うアプリケーションには、こちらを強くお勧めします)
- MVVMライトツールキットメッセンジャー
解決するには?
残念ながら、すべてを実現する優れたMVVMサンプルアプリは存在しませんし、さまざまなアプローチがあります。なぜなら、依存性注入、コマンド実行、イベント集約などの便利なツールが提供されており、自分に合ったさまざまなパターンを簡単に試すことができるからです。
プリズムのリリースです。
http://www.codeplex.com/CompositeWPF
この本には、かなりまともなサンプルアプリ(株式トレーダー)と、たくさんの小さなサンプルやHow toが含まれています。少なくとも、MVVMを実際に動作させるためによく使われるいくつかのサブパターンの良いデモンストレーションになります。CRUDとダイアログの両方の例を持っていると思います。
Prismは必ずしもすべてのプロジェクトに必要なものではありませんが、慣れておくとよいでしょう。
CRUDです。
この部分はとても簡単で、WPFの2ウェイバインディングによって、ほとんどのデータを本当に簡単に編集することができます。本当のトリックは、UIを簡単にセットアップできるようなモデルを提供することです。少なくとも、ViewModel (またはビジネスオブジェクト) が以下の機能を実装していることを確認したいものです。
INotifyPropertyChanged
を実装することで、バインディングをサポートし、プロパティをそのままUIコントロールにバインドすることができますが、同時に
IDataErrorInfo
を使用することで、検証を行うことができます。一般的に、ある種のORMソリューションを使用している場合、CRUDのセットアップは簡単です。
この記事では、簡単なCrud操作のデモンストレーションを行います。 http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx
これは LinqToSql 上に構築されていますが、この例には関係ありません。重要なのは、ビジネス・オブジェクトに
INotifyPropertyChanged
(LinqToSqlによって生成されたクラスがそうである)。MVVMはその例のポイントではありませんが、この場合は問題ないと思います。
この記事は、データバリデーションのデモです
http://blogs.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx
繰り返しになりますが、ほとんどのORMソリューションでは、すでに実装されている
IDataErrorInfo
また、通常、カスタムの検証ルールを簡単に追加するためのメカニズムも提供されています。
ほとんどの場合、ORM で作成したオブジェクト (モデル) を ViewModel でラップし、そのオブジェクトと保存/削除のコマンドを保持すれば、モデルのプロパティに直接 UI をバインドする準備ができます。
ビューは次のようなものになります(ViewModelはプロパティ
Item
は、ORM で作成されたクラスのように、モデルを保持します)。
<StackPanel>
<StackPanel DataContext=Item>
<TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
<TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
</StackPanel>
<Button Command="{Binding SaveCommand}" />
<Button Command="{Binding CancelCommand}" />
</StackPanel>
ダイアログです。
ダイアログとMVVMは少しトリッキーです。私はダイアログでMediatorアプローチの味を使うことを好みます。それについてはこのStackOverflowの質問でもう少し読むことができます。
WPF MVVMダイアログの例
古典的なMVVMとまではいかないが、私のいつものやり方は、次のようにまとめられる。
ダイアログ ViewModel の基本クラスで、コミットやキャンセルのコマンド、ダイアログを閉じる準備ができたことを知らせるイベント、その他すべてのダイアログで必要となるものを公開します。
ダイアログの一般的なビュー - これはウィンドウ、またはカスタム"モーダル"オーバーレイタイプのコントロールにすることができます。例えば、データコンテキストの変更時に、新しい ViewModel がベースクラスから継承されているかどうかを確認し、継承されている場合は、関連する close イベントを購読します (ハンドラはダイアログの結果を割り当てます)。代替の普遍的な閉じる機能 (例えば X ボタン) を提供する場合、関連する閉じるコマンドを ViewModel 上でも実行することを確認する必要があります。
ViewModels のデータテンプレートを提供する必要がある場合もありますが、特に、各ダイアログのビューを個別のコントロールにカプセル化している場合は、非常にシンプルにすることができます。ViewModel のデフォルトのデータテンプレートはこのようなものになります。
<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
<views:AddressEditView DataContext="{Binding}" />
</DataTemplate>
ダイアログビューはこれらにアクセスする必要があります。そうでなければ ViewModel をどのように表示すればよいのかが分からないからです。
<ContentControl Content="{Binding}" />
暗黙のデータテンプレートは、ビューをモデルにマッピングしますが、誰がそれを起動するのでしょうか?
ここがmvvmらしくないところです。一つの方法として、グローバルイベントを使用することができます。私がより良いと思うのは、依存性注入によって提供されるイベントアグリゲータタイプのセットアップを使用することです。この方法では、イベントはアプリ全体ではなく、コンテナに対してグローバルです。Prismはコンテナセマンティクスと依存性注入にunityフレームワークを使用しており、全体として私はUnityが非常に気に入っています。
通常、ルートウィンドウがこのイベントを購読することは理にかなっています。ダイアログを開き、そのデータコンテキストを、発生したイベントとともに渡される ViewModel に設定することができます。
このように設定することで、UIについて何も知らなくても、ViewModelsがアプリケーションにダイアログを開くように要求し、そこでユーザーのアクションに応答することができるので、ほとんどの場合、MVVMらしさは完全なままです。
しかし、UIがダイアログを立ち上げる必要がある場合もあり、その場合は少し厄介なことになります。例えば、ダイアログの位置が、それを開くボタンの位置に依存する場合を考えてみましょう。この場合、ダイアログを開くように要求するときに、UI固有の情報を持つ必要があります。私は通常、ViewModelといくつかの関連するUI情報を保持する別のクラスを作成します。残念ながら、そこではいくつかのカップリングが避けられないようです。
要素の位置データを必要とするダイアログを発生させるボタンハンドラの擬似コードです。
ButtonClickHandler(sender, args){
var vm = DataContext as ISomeDialogProvider; // check for null
var ui_vm = new ViewModelContainer();
// assign margin, width, or anything else that your custom dialog might require
...
ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
// raise the dialog show event
}
ダイアログビューは位置データにバインドし、含まれる ViewModel を内側の
ContentControl
. ViewModel自身はまだUIについて何も知りません。
一般的に、私は
DialogResult
のリターンプロパティは
ShowDialog()
メソッドを呼び出すか、ダイアログが閉じられるまでスレッドがブロックされることを期待します。非標準のモーダルダイアログは、必ずしもそのように動作しませんし、複合環境では、イベントハンドラがそのようにブロックされることを望まないことがよくあります。ViewModel の作成者は、関連するイベントのサブスクライブ、コミット/キャンセル メソッドの設定などを行うことができます。
だから、この流れの代わりに
// in code behind
var result = somedialog.ShowDialog();
if (result == ...
使っています。
// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container
私のダイアログのほとんどはノンブロッキングの疑似モーダルコントロールで、この方法で行う方が回避策を講じるよりも簡単だと思えるからです。ユニットテストも簡単です。
関連
-
[解決済み] ラジオボタンをenumにバインドするには?
-
[解決済み】WPFでMVVMを使ったダイアログの扱いについて
-
[解決済み】MVVM。最初から最後までチュートリアル?
-
[解決済み] [Solved] StackPanelの子要素をスペースアウトさせるには?
-
[解決済み] ユーザーコントロールライブラリーとカスタムコントロールライブラリーの違いは何ですか?
-
[解決済み] DataTrigger where value is NOT null?
-
[解決済み] WPF フォントのぼやけ問題- 解決策
-
[解決済み] MVVMテンプレートの好例
-
[解決済み] Prism for WPFとは?
-
[解決済み] グリッドカラムの幅・高さを設定する際の「Auto」と「*」の違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
WPFバインディング(データバインディング)の使用方法
-
[解決済み] ラジオボタンをenumにバインドするには?
-
[解決済み] Windows 8 ランタイム(WinRT / Windowsストアアプリ / Windows 10 ユニバーサルアプリ)とSilverlightやWPFの比較はどうですか?[クローズド]
-
[解決済み] [Solved] StackPanelの子要素をスペースアウトさせるには?
-
[解決済み] ユーザーコントロールライブラリーとカスタムコントロールライブラリーの違いは何ですか?
-
[解決済み] wpf: ボタンがコマンドによって無効にされたとき、ツールチップを表示する方法は?
-
[解決済み] WPF TemplateBindingとRelativeSource TemplatedParentの比較
-
[解決済み] WPF フォントのぼやけ問題- 解決策
-
[解決済み] MVVMテンプレートの好例
-
[解決済み] WPF: スクロールバー付きItemsControl (ScrollViewer)