MVVMパターンを使用していくつかのプロジェクトを行った後、私はまだViewModelの役割に苦労しています。
過去に行ったこと:モデルをデータコンテナとしてのみ使用する。 ViewModelでデータを操作するロジックを配置します。 (ビジネスロジックは正しいですか?)欠点:ロジックは再利用できません。
私が今試していること:ViewModelを可能な限り薄く保つ。すべてのロジックをモデルレイヤーに移動します。 ViewModelでのみプレゼンテーションロジックを保持します。短所:データがモデルレイヤー内で変更されると、UI通知が非常に苦痛になります。
したがって、より明確にするために例を示します。
シナリオ:ファイルの名前を変更するツール。クラス:File:各ファイルを表します。ルール:ファイルの名前を変更するロジックが含まれています。
アプローチ1に従っている場合:ファイル、ルール、およびビューのViewModelの作成-> RenamerViewModel。 RenamerViewModelにすべてのロジックを配置する:FileViewModelとRuleViewModelのリストと進行するロジックを含む。簡単で高速ですが、再利用できません。
アプローチ2に従っている場合:ファイルのリストを含む新しいモデルクラス->リネーマーを作成する場合、各ファイルを相互に関連付けて各ルールを適用するためのルールと進行中のロジック。ファイル、ルール、リネーマーのビューモデルを作成します。現在、RenamerViewModelにはRenamer Modelのインスタンスと、RenamerのFile und Rule Listをラップする2つのObservableCollectionのみが含まれています。ただし、ロジック全体はRenamer Modelにあります。そのため、メソッド呼び出しによって一部のデータを操作するためにリネームモデルがトリガーされた場合、ViewModelにはどのデータが操作されているのかがわかりません。モデルにはPropertyChange通知が含まれていないため、これは回避します。そのため、ビジネスロジックとプレゼンテーションロジックは分離されていますが、これによりUIへの通知が難しくなります。
ビューモデル内にビジネスロジックを配置することは物事を行うための非常に悪い方法ですので、私はすぐに決して言わないつもりです 2番目のオプション。
モデル内にロジックを配置することは、はるかに合理的であり、素晴らしい開始アプローチです。欠点は何ですか?あなたの質問は言う
そのため、メソッド呼び出しによって一部のデータを操作するためにリネームモデルがトリガーされた場合、ViewModelにはどのデータが操作されているのかがわかりません。モデルにはPropertyChange通知が含まれていないため、これは回避します。
さて、モデルにINotifyPropertyChanged
を実装させることで、より良いものに進むことができます。ただし、それができない場合があることは事実です。たとえば、モデルは、ツールによってプロパティが自動生成され、変更通知を発生させない部分クラスである場合があります。それは残念ですが、世界の終わりではありません。
何かを購入したい場合は、誰かがそれを支払わなければなりません。そのような通知を行うモデルではない場合、2つの選択肢しかありません。
事実上、ビューモデル内に「ビジネスロジック」を配置することに戻っているため、最初のオプションはやはり悪い考えです。ビューモデルにビジネスロジックをall入れるほど悪くはありませんが、それでもです。
2番目のオプションは、より有望です(そして、残念ながら、実装するためにより多くの作業があります):
両方のアプローチは有効ですが、3番目のアプローチがあります。モデルとVMレイヤーの間にサービスを実装します。モデルを愚かにしたい場合は、再利用可能な方法でビジネスルールを実施できます。
モデルにはPropertyChange通知が含まれていないため、それを避けるため
なぜこれを避けているのですか?誤解しないでください。私はモデルをできるだけ馬鹿にする傾向がありますが、モデルに変更通知を実装すると役立つ場合があり、System.ComponentModel
するとき。それは完全にUIに依存しません。
私は次のことをします
XAMLビューロジックのみで表示
クリックハンドラーを処理し、新しいビューモデルを作成するViewModel。ルーティングイベントなどを処理します。
モデルデータの検証に関するデータコンテナーおよびビジネスロジックであるモデル。
モデルにデータを取り込むサービス。たとえば、Webサーバーを呼び出し、ディスクからロードし、ディスクに保存します。例によっては、モデルとサービスの両方でIPropertyChangedを実装することがよくあります。または、代わりにイベントハンドラーがある場合があります。
複雑なアプリケーションの場合は、別のレイヤーが必要です。モデル+サービス、ビュー、ビューモデルと呼びます。このサービスはビジネスロジックを抽象化し、モデルインスタンスを依存関係として取得するか、モデルを作成します。
ModelとViewModelの両方にIDataErrorInfoを実装することもできますが、Modelでのみ検証を行うため、Modelでのみビジネスルールを実装する方法が簡単になります...
例:
ViewModel:
...
private Person person;
...
string IDataErrorInfo.this[string propertyName]
{
get
{
string error = (person as IDataErrorInfo)[propertyName];
return error;
}
}
モデル:
public class Person:INotifyPropertyChanged,IDataErrorInfo
{
...
string IDataErrorInfo.this[string propertyName]
{
get { return this.GetValidationError(propertyName); }
}
...
string GetValidationError(string propertyName)
{
if(propertyName == "PersonName")
//do the validation here returning the string error
}
}
さらに、MVCVMパターンを見てください。実際にそれを使用していますが、ビジネスロジックをモデルやビューモデルではなくコントローラークラスに抽象化するのはかなり問題ありません。