MVVMテンプレートの良い例


141

私は現在、Microsoft MVVMテンプレートを使用していますが、詳細な例が不足していることに不満を感じています。含まれているContactBookの例はコマンドの処理をほとんど示していません。また、コンセプトが類似しているが少し複雑なアプローチを使用していても複雑さに欠けているMSDN Magazineの記事からの唯一の例を見つけました。少なくとも基本的なCRUD操作とダイアログ/コンテンツの切り替えを示す適切なMVVMの例はありますか?


皆の提案は本当に役に立ちました、そして私は良いリソースのリストを編集し始めます

フレームワーク/テンプレート

お役立ち記事

スクリーンキャスト

追加のライブラリ


これらのリソースが役に立ったことを嬉しく思います。私は現在、2番目の本番MVVMアプリケーションを使用しており、出会った初心者に役立つコンテンツを引き続き追加します。
jwarzech 2010年

回答:


59

残念ながら、すべてを実行する優れたMVVMサンプルアプリはありません。また、物事を行うためのさまざまなアプローチがあります。まず、そこにあるアプリフレームワークの1つに慣れることをお勧めします(Prismはまともな選択です)。依存関係の注入、コマンド、イベントの集計などの便利なツールを提供して、自分に合ったさまざまなパターンを簡単に試すことができるからです。 。

プリズムリリース:http :
//www.codeplex.com/CompositeWPF

これには、かなりまともなサンプルアプリ(株式トレーダー)が含まれ、多数の小さなサンプルとその方法が含まれています。少なくとも、MVVMを実際に機能させるために人々が使用するいくつかの一般的なサブパターンの優れたデモンストレーションです。CRUDとダイアログの両方の例があると思います。

Prismは必ずしもすべてのプロジェクトに必要なわけではありませんが、慣れることは良いことです。

CRUD: この部分は非常に簡単です。WPF双方向バインディングにより、ほとんどのデータの編集が本当に簡単になります。本当のトリックは、UIのセットアップを簡単にするモデルを提供することです。少なくとも、ViewModel(またはビジネスオブジェクト)がINotifyPropertyChangedバインディングをサポートするように実装し、プロパティをUIコントロールに直接バインドできることを確認する必要がありますがIDataErrorInfo、検証のために実装することもできます。通常、ある種のORMソリューションを使用する場合、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をモデルのプロパティに直接バインドする準備が整います。

ビューは次のようになります(ItemORMで作成されたクラスのように、ViewModelにはモデルを保持するプロパティがあります)。

<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でも関連するクローズコマンドを実行する必要があります。

ViewModelのデータテンプレートを提供する必要がある場所では、特に、ダイアログごとに個別のコントロールにカプセル化されたビューがあるため、テンプレートは非常に単純です。その場合、ViewModelのデフォルトのデータテンプレートは次のようになります。

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>

ダイアログビューはこれらにアクセスする必要があります。そうしないと、ViewModelを表示する方法がわからないため、共有ダイアログUIを除いて、その内容は基本的に次のようになります。

<ContentControl Content="{Binding}" />

暗黙的なデータテンプレートはビューをモデルにマップしますが、誰がそれを起動しますか?

これはnot-so-mvvmの部分です。これを行う1つの方法は、グローバルイベントを使用することです。依存関係の注入によって提供されるイベントアグリゲータータイプのセットアップを使用することをお勧めします。これにより、イベントはアプリ全体ではなく、コンテナーに対してグローバルになります。Prismはコンテナーのセマンティクスと依存関係の注入にUnityフレームワークを使用しており、全体としてUnityはかなり好きです。

通常、ルートウィンドウがこのイベントをサブスクライブすることは理にかなっています。ダイアログを開き、発生したイベントで渡されるViewModelにデータコンテキストを設定できます。

これをこのように設定すると、ViewModelはアプリケーションにダイアログを開き、UIについて何も知らなくてもそこでユーザーのアクションに応答するように要求できます。そのため、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について何も知りません。

一般にDialogResultShowDialog()メソッドのreturnプロパティを使用しないか、ダイアログが閉じるまでスレッドがブロックすることを期待しません。非標準のモーダルダイアログは常にそのように動作するとは限らず、複合環境では、イベントハンドラーがそのようにブロックすることを本当に望まないことがよくあります。私はViewModelでこれを処理することを好みます。ViewModelの作成者は、関連するイベントをサブスクライブしたり、コミット/キャンセルメソッドを設定したりできるため、このUIメカニズムに依存する必要はありません。

したがって、このフローの代わりに:

// 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

私のダイアログのほとんどはノンブロッキングの疑似モーダルコントロールであり、このようにすることは、回避するよりも簡単に思えるので、私はこの方法を好みます。単体テストも簡単です。


詳細な回答ありがとうございます!最近、私の最大の問題は、アプリケーションのフローを処理するためにMainViewModelが他のビューモデルと通信する必要がある場合であることがわかりました。しかし、MVVM + Mediatorが人気のあるアプローチのようです。
jwarzech 2009

2
Mediatorは間違いなく役立ちます。イベントアグリゲーターパターン(Prismは適切に実装されています)は、低カップリングが目標である場合にも非常に役立ちます。また、メインのビューモデルには通常、独自の子ビューモデルがあり、それらとの通信に問題はありません。子ビューモデルが、UIを含め、必ずしも把握していないアプリ内の他のモジュールとやり取りする必要がある場合は、メディエーターまたはイベントアグリゲーターを使用する必要があります(私のダイアログの例はこの特定のケースに関するものです)。
エゴール

1
ダイアログとウィンドウを操作するためのガイドラインは非常に役に立ちました。しかし、いくつかの問題に悩まされています。1.ビューからウィンドウタイトルをどのように設定しますか?2.オーナーウィンドウの設定をどのように扱いますか?
djskinner 2010年

@Daniel Skinner:ここでダイアログについて話していると思いますが、私が間違っていれば訂正してください。ダイアログタイトルは別のプロパティであり、好きなようにバインドできます。ベースダイアログのviewmodelクラス(titleプロパティがあるとしましょう)で私のアプローチを実行した場合、すべての汎用ダイアログウィンドウでUIからUIへのバインディングを使用して、タイトルを{Binding Path = DataContext.Title、ElementName =に設定できます。 NameOfContentPresenter}。オーナーウィンドウは少しトリッカーです。つまり、実際にダイアログをポップアップするメディエーターは、ルートアプリビューについて知る必要があります。
Egor

実際、私はそれを取り戻します-ある時点でこれをどのように構成するかに関係なく、ダイアログを実際にポップアップしている人は誰でも、ルートアプリウィンドウ/ビューへの参照を持つ必要があります。「通常、ルートウィンドウがこのイベントをサブスクライブすることは理にかなっています。ダイアログを開いて、発生したイベントで渡されるビューモデルにデータコンテキストを設定できます。」ここで所有者を設定します。
Egor

6

Jason Dolinger がMVVMの優れたスクリーンキャストを作成しました。エゴールが述べたように、良い例はありません。彼らはすべて終わった。ほとんどは良いMVVMの例ですが、複雑な問題に遭遇した場合はそうではありません。誰もが独自の方法を持っています。Laurent Bugnionには、ビューモデル間で通信するための良い方法もあります。 http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-messenger-v2-beta.aspx Cinchも良い例です。Paul Stovelは、彼のMagellanフレームワークで多くを説明する良い投稿をしています。


3

カリバーンを見たことがありますか?ContactManagerサンプルには、多くの優れた機能が含まれています。一般的なWPFサンプルも、コマンドの概要を示しています。ドキュメントはかなり良く、フォーラムはアクティブです。おすすめ!





2

私もあなたの欲求不満を共有しました。私はアプリケーションを書いていて、次の3つの要件がありました。

  • 拡張可能
  • MVVMを使用したWPF
  • GPL互換の例

私が見つけたのはほんの少しだけだったので、私はそれをできる限りベストに書き始めました。少し理解してから、参照アプリケーションを使用できる他の人(自分のような)がいる可能性があることに気づいたので、汎用的なものをWPF / MVVMアプリケーションフレームワークにリファクタリングし、LGPLでリリースしました。私はそれをSoapBox Coreと名付けました。ダウンロードページに移動すると、小さなデモアプリケーションが付属しており、そのデモアプリケーションのソースコードもダウンロードできます。お役に立てば幸いです。また、詳細情報が必要な場合は、scott {at} soapboxautomation.comにメールを送ってください。

編集:それがどのように機能するかを説明するCodeProjectの記事も投稿しました。


2

コードプロジェクトのゼロから簡単なMVVMの例をここに記述しました。これはMVVM WPFのリンクです。それは単純な3層アーキテクチャから始まり、PRISMのようないくつかのフレームワークを使用するように卒業します。

ここに画像の説明を入力してください


1

その問題を自分の手に渡るまで、私は欲求不満を共有しました。IncEditorを起動しました。

IncEditor(http://inceditor.codeplex.com)は、WPF、MVVM、およびMEFを開発者に紹介しようとするエディターです。私はそれを開始し、「テーマ」サポートのようないくつかの機能をなんとか手に入れました。私はWPF、MVVM、MEFの専門家ではないので、多くの機能を組み込むことはできません。私のような熟練者がそれをよりよく理解できるように、私は皆さんにそれをより良くするために誠実な要求をします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.