MVVMの基本概念— ViewModelは何をすべきですか?


83

MVVMの概念を理解しようとして、私はすでにいくつかのブログを読み、いくつかのプロジェクトを見てきました。

私が理解していることから、ビューはばかげている、それはそれに渡される何かを提示する方法を知っているだけです。

モデルは単なるデータであり、ViewModelは、2つの間のパディングのように機能するものであり、モデルから情報を取得してビューに渡し、ビューはそれを表示する方法を知っている必要があります。または逆に、ビューの情報が変更された場合は、その変更をモデルに渡す必要があります。

しかし、私はまだその概念をどのように適用するのか分かりません。コンセプトを理解できるように、誰かが非常に単純なシナリオを説明できますか?私はすでにいくつかのプロジェクトを見てきましたが、それでも完全には意味がないので、誰かが平易な英語でそれを書き出すことができれば、それは素晴らしいことです。


2
「渡されたものを提示する方法を知っているだけ」という見解に同意することはできません。ビューはVMからデータを取得します。誰もそれにデータを渡しません。誰もビューについて知りません。これはMVPとの重要な違いです。MVP(uは、コードビハインドロジックを備えた単純なWPFアプリケーションと考えることができます。これはMVPパターンです)コードビハインドは、前述のようにデータをViewに渡すプレゼンターです。
グリゴリー2011年

回答:


146

私はそれをこのように考えるのが好きです:

あなたが言うように、ビューはばかげています。MVVMに関する独創的で頻繁にリンクされているMSDN記事のライターであるJoshSmithは、ビューは「データが着る服」であると述べています。ビューに実際にデータが含まれたり、データを直接操作したりすることはありません。ビューモデルのプロパティとコマンドにバインドされるだけです。

モデルは、ビジネスオブジェクトと同様に、アプリケーションのドメインをモデル化するオブジェクトです。アプリケーションはミュージックストアですか?おそらく、モデルオブジェクトはアーティスト、アルバム、曲になります。アプリケーションは組織図ブラウザですか?おそらく、モデルオブジェクトはマネージャーと従業員になります。これらのモデルオブジェクトは、いかなる種類のビジュアルレンダリングにも関連しておらず、それらを配置するアプリケーションにも直接関連していません。モデルオブジェクトは、ある種を表すオブジェクトのファミリとして、それ自体で完全に意味をなす必要があります。ドメインの。モデルレイヤーには通常、サービスアクセサーなども含まれます。

これにより、Viewmodelsが表示されます。彼らは何ですか?これらは、GUIアプリケーションをモデル化するオブジェクトです。、つまり、ビューで使用されるデータと機能を提供します。これらは、構築している実際のアプリケーションの構造と動作を定義するものです。モデルオブジェクトの場合、ドメインは選択したドメイン(ミュージックストア、組織図ブラウザーなど)ですが、ビューモデルの場合、ドメインはグラフィカルアプリケーションです。ビューモデルは、アプリケーションが実行するすべての動作とデータをカプセル化します。それらは、オブジェクトやリストをプロパティとして公開するだけでなく、コマンドなども公開します。コマンドは、それを運ぶオブジェクトにラップされた単なる動作(最も単純なメソッド呼び出し)です。ビューは、オブジェクトにビジュアルコントロールをアタッチするデータバインディングによって駆動されるため、このアイデアは重要です。MVVMでは、ボタンにクリックハンドラーメソッドを指定しません。

私にとって、最も紛らわしい点は次のとおりです。

  • ビューモデルはグラフィカルアプリケーションのモデルですが、視覚的な概念を直接参照したり使用したりすることはありません。たとえば、ViewModelsでWindowsコントロールへの参照を必要としない場合、それらはビューに表示されます。ViewModelは、データと動作を、それらにバインドするコントロールまたはその他のオブジェクトに公開するだけです。たとえば、リストボックスを含むビューはありますか?あなたのビューモデルには、ほぼ確実に何らかのコレクションが含まれています。ビューにボタンはありますか?ビューモデルには、ほぼ確実にいくつかのコマンドが含まれています。
  • 「ビューモデル」と見なすことができるオブジェクトにはいくつかの種類があります。理解するのが最も簡単な種類のビューモデルは、1:1の関係でコントロールまたは画面を直接表すものです。たとえば、「画面XYZにはテキストボックス、リストボックス、および3つのボタンがあるため、ビューモデルには文字列、コレクション、と3つのコマンド。」ビューモデルレイヤーに適合する別の種類のオブジェクトは、モデルオブジェクトのラッパーであり、モデルオブジェクトに動作を与え、ビューでより使いやすくします。ここで、「厚い」および「薄い」ビューモデルレイヤーの概念を理解します。「薄い」ビューモデルレイヤーは、モデルオブジェクトをビューに直接公開するビューモデルのセットです。つまり、ビューは最終的にモデルオブジェクトのプロパティに直接バインドされます。これは、単純な読み取り専用ビューなどで機能します。しかし、各オブジェクトに関連付けられた動作が必要な場合はどうでしょうか。モデルはアプリケーションに関連しておらず、ドメインにのみ関連しているため、モデルにそれを含める必要はありません。モデルオブジェクトをラップし、よりバインディングに適したデータと動作を提供するオブジェクトに配置できます。このラッパーオブジェクトもビューモデルと見なされ、それらを持つと「より厚い」ビューモデルレイヤーになり、ビューがモデルクラス上の何かに直接バインドされることはありません。コレクションには、モデル自体を含めるだけでなく、モデルをラップするビューモデルが含まれます。モデルオブジェクトをラップし、よりバインディングに適したデータと動作を提供するオブジェクトに配置できます。このラッパーオブジェクトもビューモデルと見なされ、それらを持つと「より厚い」ビューモデルレイヤーになり、ビューがモデルクラスの何かに直接バインドされることはありません。コレクションには、モデル自体を含めるだけでなく、モデルをラップするビューモデルが含まれます。モデルオブジェクトをラップし、よりバインディングに適したデータと動作を提供するオブジェクトに配置できます。このラッパーオブジェクトもビューモデルと見なされ、それらを持つと「より厚い」ビューモデルレイヤーになり、ビューがモデルクラス上の何かに直接バインドされることはありません。コレクションには、モデル自体を含めるだけでなく、モデルをラップするビューモデルが含まれます。

うさぎの穴はさらに深くなります-MVVMを機能させ続けるValueConvertersのように理解すべきイディオムはたくさんあり、ブレンド可能性、テスト、アプリでデータを渡す方法などについて考え始めるときに適用することがたくさんあります。各ビューモデルは必要な動作にアクセスできますが(これが依存性注入の出番です)、うまくいけば上記が良いスタートです。重要なのは、ビジュアル、ドメイン、実際のアプリケーションの構造と動作を3つの異なるものとして考えることです。


3
+ 1-いくつかのサンプルコードで検出された「ラッパー」ViewModelに混乱したため、ここに行き着きました。私のためにそれをクリアしてくれてありがとう:
Riegardt Steyn 2013

1
素晴らしい答え-私が+10できたらいいのに。
Nick Hodges

1
@nlawalker非常に素晴らしいです!上記の2ビットのコメントは非常に長い間私を混乱させてきました。多くの記事やブログはMVVMの「主要な機能」を説明しているだけですが、それを利用しようとすると、物事は非常に複雑になり始めます!「これらのビューをナビゲートする方法は?」など。「ViewModelsを設計するときの適切な粒度はどれくらいですか?」「ビューに一致するViewModelが必要ですか、それとも1つのViewModelを別のビューで再利用できますか?」「スリムVM」と「​​シックVM」で構成されるViewModelについて明確にすることは、本当に理にかなっています。試してみましたが、うまく機能します。はるかに!:)
クロー

@nlawalkerありがとう!そして別の質問:私はtreeViewを持っていて、TreeViewViewModelを作成します。したがって、ViewModelで:ExpandTree()のようなメソッドを作成するとします。それは正しい方法ですか?
user2545071 2015

うわー、これは素晴らしい記事です、かなり良い仕事@nlawalker
Vivek Shukla

25

この非常に役立つ記事をソースとして使用しViewViewModel、およびModelの概要を示します


見る:

  • ビューは、ウィンドウ、ページ、ユーザーコントロール、データテンプレートなどの視覚要素です。ビューは、ビューに含まれるコントロールとその視覚的なレイアウトおよびスタイルを定義します。

  • ビューは、そのDataContextプロパティを介してビューモデルを参照します。ビュー内のコントロールは、ビューモデルによって公開されるプロパティとコマンドにバインドされたデータです。

  • ビューは、ビューとビューモデル間のデータバインディング動作をカスタマイズできます。たとえば、ビューは値コンバーターを使用してUIに表示されるデータをフォーマットしたり、検証ルールを使用して追加の入力データ検証をユーザーに提供したりできます。

  • ビューは、ビューモデルの状態変化から、またはユーザーのUIとの対話を介してトリガーされる可能性のあるアニメーションや遷移など、UIの視覚的動作を定義および処理します。

  • ビューのコードビハインドは、XAMLで表現するのが難しい、またはビューで定義された特定のUIコントロールへの直接参照を必要とする視覚的な動作を実装するUIロジックを定義する場合があります。

注:
ビューモデルはビュー内の特定の視覚要素に関する明確な知識を持ってはならないため、ビュー内の視覚要素をプログラムで操作するコードは、ビューのコードビハインドに存在するか、動作にカプセル化されている必要があります。


モデルの表示:

  • ビューモデルは非ビジュアルクラスであり、WPFまたはSilverlight基本クラスから派生したものではありません。これは、アプリケーションでユースケースまたはユーザータスクをサポートするために必要なプレゼンテーションロジックをカプセル化します。ビューモデルは、ビューとモデルに関係なくテスト可能です。

  • ビューモデルは通常、ビューを直接参照しません。ビューがデータバインドできるプロパティとコマンドを実装します。INotifyPropertyChangedおよびINotifyCollectionChangedインターフェイスを介した変更通知イベントを介して、状態の変更をビューに通知します。

  • ビューモデルは、ビューとモデルの相互作用を調整します。データを変換または操作して、ビューで簡単に使用できるようにしたり、モデルに存在しない可能性のある追加のプロパティを実装したりする場合があります。また、IDataErrorInfoまたはINotifyDataErrorInfoインターフェイスを介してデータ検証を実装する場合もあります。

  • ビューモデルは、ビューがユーザーに視覚的に表すことができる論理状態を定義する場合があります。

注:
アプリケーションの論理的な動作にとって重要なものはすべて、ビューモデルに入れる必要があります。データバインディングを介してビューに表示されるデータ項目を取得または操作するコードは、ビューモデルに存在する必要があります。


モデル:

  • モデルクラスは、アプリケーションのデータとビジネスロジックをカプセル化する非ビジュアルクラスです。彼らは、アプリケーションのデータを管理し、必要なビジネスルールとデータ検証ロジックをカプセル化することによってその一貫性と有効性を確保する責任があります。

  • モデルクラスは、ビューまたはビューモデルクラスを直接参照せず、それらの実装方法に依存しません。

  • モデルクラスは通常、INotifyPropertyChangedおよびINotifyCollectionChangedインターフェイスを介してプロパティおよびコレクションの変更通知イベントを提供します。これにより、ビューでデータを簡単にバインドできます。オブジェクトのコレクションを表すモデルクラスは、通常、ObservableCollection<T>クラスから派生します。

  • モデルクラスは通常、IDataErrorInfoまたはINotifyDataErrorInfoインターフェイスを介してデータ検証とエラーレポートを提供します。

  • モデルクラスは通常、データアクセスとキャッシュをカプセル化するサービスまたはリポジトリと組み合わせて使用​​されます。


17

私はこれをMVVMのこのシリーズで考えることができるように「平易な英語」で書きました。特に、この図はおそらく最も単純で短い説明です。

そうは言っても、基本的に「モデル」はデータまたはビジネスルールです。それがどのように、どこで使用されるのか、特にどのテクノロジーがそれを使用するのかについては、本当に知らないはずです。「モデル」はアプリケーションの中核であり、アプリケーションがWPF、Silverlight、Windowsフォーム、ASP.NETなどであるかどうかを心配する必要はありません。純粋な形式の「それ自体」です。

「ビュー」は、完全にテクノロジー固有の部分です。MVVMでは、理想的には、ビューはほぼ100%XAMLである必要があります。これにより、柔軟性が大幅に向上します。

ただし、モデルからの情報を、手元のテクノロジーで使用できる形式に変換するものが必要です。ここで、ViewModelが機能します。たとえば、これは多くの場合、コマンド(ロジックを実行するため)、実装INotifyPropertyChanged(データバインディングサポートのため)などを含む特定のデータのモデルクラスを「ViewModel」に「ラップ」します。それだけです-モデルを作成するのはブリッジですビューで使用できます。


わかりました、ありがとう。ビューがモデルの「オブジェクト」を理解できるように、モデルをオブジェクトとして、ViewModelをオブジェクトを処理する方法として考えました。しかし、これは間違っていると言われました。ViewModel自体もオブジェクトです。これが私を本当に混乱させているものだと思います。
RKM 2011年

@Rosie:引用したシリーズを読む(または少なくともスキミングする)ことをお勧めします。MVCやMVPなどを理解しているとはまだ想定していないMVVMに関する記事がほとんどないため、具体的に書きました。これは実際には「段階的な」移行です;)
Reed Copsey 2011年

これを実現するのは少しゾンビですか...あなたの図は、VMに「アプリケーション固有の状態とロジック」が含まれていることを示しています(私の強調)。これは、VMにデータQAロジックを含めることができる/含める必要があると考えていることを示唆していますか?関連するRssWpfMVVM.csprojには、2つのビューモデルに明らかなQAがないようです。
ラフィン2015

1

MVVMのすばらしい紹介は、JasonDolingerのビデオにあります。私が始めたとき、私はかなり長い間ビデオを持っていました、それは本当に役に立ちます。


1
リンクが
切れています

1
@ ibrahimmahrir〜有効なURLへのリンクを更新しました。私は今ビデオをダウンロードしています。
inteXX

0

基になるモデル上で一貫したファサードを提示するViewModelの構築は、見た目よりもはるかに複雑になる可能性があります。ViewModelオブジェクトの構築に関するこの記事では、ViewModelの構築方法を示し、発生する可能性のあるいくつかの問題と、合理的な解決策のように見えるものについて説明します。それを読んだとき、コレクションの扱いに関するセクションがありませんでしたが、それでもいくつかの興味深い点があります。

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