私が経験したほとんどのMVVMの例では、ModelがINotifyPropertyChangedを実装していましたが、 Josh SmithのCommandSinkの例ViewModel INotifyPropertyChangedを実装します。
私はまだ認知的にMVVMの概念をまとめているので、次の場合にはわかりません:
あなたが取り組んできたMVVMプロジェクトで他の人はどのような経験をしましたか?
私はまったく反対だと思います、私は常にINotifyPropertyChanged
をViewModelに置きます-あなたは本当にINotifyPropertyChanged
のようなかなりWPF固有の機能でモデルを汚染したくありません。 ViewModelに座ってください。
他の人も意見が違うと思いますが、それが私のやり方です。
モデルがINotifyPropertyChanged
を実装すべきではないという概念には強く反対します。このインターフェイスはUI固有ではありません!変更を通知するだけです。実際、WPFはこれを使用して変更を識別しますが、それがUIインターフェイスであることを意味するわけではありません。これを次のコメントと比較します。「タイヤはカーアクセサリーです」。確かにありますが、自転車、バスなども使用します。 要約すると、そのインターフェースをUIのものとして受け取らないでください。
そうは言っても、必ずしもモデルが通知を提供するべきだと思うとは限りません。 実際、経験則として、必要でない限り、モデルはこのインターフェイスを実装すべきではありません。サーバーデータがクライアントアプリにプッシュされないほとんどの場合、モデルは古くなる可能性があります。しかし、金融市場のデータを聞いていると、モデルがインターフェイスを実装できない理由がわかりません。例として、特定の値の買値または売値を受け取ったときにアラートを発行するサービス(電子メールなど)または注文するサービスなどの非UIロジックがある場合はどうなりますか?これは、クリーンなソリューションになる可能性があります。
しかし、物事を達成するさまざまな方法がありますが、私は常に単純さを支持し、冗長性を避けることを主張します。
何が良いですか?コレクションでのイベントまたはプロパティの変更をビューモデルで定義し、それをモデルに伝播するか、ビューが本質的にモデルを更新する(ビューモデルを介して)か?
「これができない、またはthat」と主張している人を見かけたら、それは彼らが何について話しているのかわからないサインです。
それは本当にあなたのケースに依存し、実際MVVMは多くの問題を抱えたフレームワークであり、MVVMの一般的な実装はまだ見ていません。
MVVMの多くのフレーバーと、主に他の開発者によって提供される一般的な問題に対するいくつかの解決策を説明する時間があればいいのですが、また別の機会にやらなければならないと思います。
M-V-VMでは、ViewModelは常に(常にではないモデル)INotifyPropertyChangedを実装します
http://blogs.msdn.com/llobo/archive/2009/05/01/download-mv-vm-project-template-toolkit.aspx からMV-VMプロジェクトテンプレート/ツールキットを確認してください。 =。コマンドにはDelegateCommand
を使用し、M-V-VMプロジェクトの優れた開始テンプレートになるはずです。
MVVMの名前は非常に不適切であり、ViewModelをViewModelと呼ぶと、多くの人が適切に設計されたアーキテクチャの重要な機能を見逃してしまいます。
View-ModelをDataControllerのように考え、DataControllerがデータに触れる唯一のアイテムであるアーキテクチャを実装する場合、データに直接触れることはありませんが、常にDataControllerを使用します。 DataControllerはUIにとっては便利ですが、必ずしもUIだけではありません。ビジネスレイヤー、UIレイヤーなど用です。
DataModel -------- DataController ------ View
/
Business --------/
このようなモデルになります。ビジネスでさえ、ViewModelを使用してデータにのみアクセスする必要があります。その後、あなたの難問は消え去ります。
モデルの実装方法によって異なります。私の会社は、LhotkaのCSLAオブジェクトと同様のビジネスオブジェクトを使用し、ビジネスモデル全体でINotifyPropertyChangedを広範囲に使用しています。
検証エンジンは、このメカニズムを通じてプロパティが変更されることを通知されることに大きく依存しており、非常にうまく機能します。明らかに、変更の通知が操作にとってそれほど重要ではないビジネスオブジェクト以外の異なる実装を使用している場合、ビジネスモデルの変更を検出する他の方法があるかもしれません。
また、必要に応じてモデルからの変更を伝播するビューモデルもありますが、ビューモデル自体は、基礎となるモデルの変更をリッスンしています。
Pauloの答えに同意します。ModelsにINotifyPropertyChanged
を実装することは完全に受け入れられ、Microsoftによっても提案されています-
通常、モデルはビューへのバインドを容易にする機能を実装します。これは通常、
INotifyPropertyChanged
およびINotifyCollectionChanged
インターフェイスを介したプロパティおよびコレクションの変更通知をサポートすることを意味します。オブジェクトのコレクションを表すモデルクラスは通常、ObservableCollection<T>
クラス。INotifyCollectionChanged
インターフェイスの実装を提供します。
そのタイプの実装が必要かどうかはあなた次第ですが、覚えておいてください-
モデルクラスが必要なインターフェイスを実装していない場合はどうなりますか?
場合によっては、
INotifyPropertyChanged
、INotifyCollectionChanged
、IDataErrorInfo
、またはINotifyDataErrorInfo
インターフェイスを実装しないモデルオブジェクトを使用する必要があります。これらの場合、ビューモデルはモデルオブジェクトをラップし、必要なプロパティをビューに公開する必要があります。これらのプロパティの値は、モデルオブジェクトによって直接提供されます。ビューモデルは、公開するプロパティに必要なインターフェイスを実装するため、ビューはそれらに簡単にデータバインドできます。
から取得- http://msdn.Microsoft.com/en-us/library/gg405484(PandP.40).aspx
モデルにINotifyPropertyChanged
を実装していないプロジェクトで働いてきましたが、これが原因で多くの問題に直面しました。プロパティの不必要な複製がVMで必要であり、同時に、BL/DLに渡す前に、基礎となるオブジェクトを更新された値で更新する必要がありました。
モデルオブジェクトのコレクション(編集可能なグリッドやリストなど)や複雑なモデルを扱う必要がある場合は、特に問題に直面します。モデルオブジェクトは自動的に更新されず、VMですべてを管理する必要があります。
しかし、(このプレゼンテーションのように リンクテキスト )モデルはサービスであり、アプリケーションにオンラインでデータを提供し、イベントを使用して新しいデータが到着したか、データが変更されたという通知を実装する必要があります...
MV-VMに固執したい場合、答えは非常に明確だと思います。
参照: http://msdn.Microsoft.com/en-us/library/gg405484(v = PandP.40).aspx
MVVMパターンでは、ビューはUIとUIロジックをカプセル化し、ビューモデルはプレゼンテーションロジックと状態をカプセル化し、モデルはビジネスロジックとデータをカプセル化します。
「ビューは、データバインディング、コマンド、変更通知イベントを介してビューモデルと対話します。ビューモデルは、モデルの更新をクエリ、監視、調整し、ビューでの表示に必要なデータを変換、検証、集計します。」
私はあなたのViewModelで言うでしょう。モデルはUIに依存しないため、モデルの一部ではありません。モデルは「ビジネスにとらわれないものすべて」でなければなりません
モデルではなくビューモデルでINotifyPropertyChange
を使用するだけで、
通常、モデルはIDataErrorInfo
を使用して検証エラーを処理するため、ViewModelを保持するだけで、MVVMを使用できます。
すべてはユースケースに依存すると思います。
多数のプロパティを持つ単純なモデルがある場合、INPCを実装することができます。単純に言うと、このモデルは [〜#〜] poco [〜#〜] のように見えることを意味します。
モデルがより複雑で、インタラクティブモデルドメイン(モデルを参照するモデル、他のモデルのイベントをサブスクライブするモデル)に住んでいる場合、INPCとしてモデルイベントを実装するのは悪夢です。
他のモデルと協力する必要があるモデルエンティティの位置に身を置いてください。購読するさまざまなイベントがあります。それらはすべてINPCとして実装されています。持っているイベントハンドラーを想像してください。 if-clausesおよび/またはswitch claussesの1つの巨大なカスケード。
INPCの別の問題。実装ではなく抽象化に依存するようにアプリを設計する必要があります。これは通常、インターフェイスを使用して行われます。
同じ抽象化の2つの異なる実装を見てみましょう。
public class ConnectionStateChangedEventArgs : EventArgs
{
public bool IsConnected {get;set;}
}
interface IConnectionManagerINPC : INotifyPropertyChanged
{
string Name {get;}
int ConnectionsLimit {get;}
/*
A few more properties
*/
bool IsConnected {get;}
}
interface IConnectionManager
{
string Name {get;}
int ConnectionsLimit {get;}
/*
A few more properties
*/
event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged;
bool IsConnected {get;}
}
次に、両方を見てください。 IConnectionManagerINPCから何がわかりますか?そのプロパティの一部が変更される可能性があること。あなたはそれらのどれがわからない。実際には、IsConnectedの変更のみが設計されており、残りの変更は読み取り専用です。
反対に、IConnectionManagerの意図は明確です。「IsConnectedプロパティの値が変更される可能性があることを伝えることができます」。
モデルがViewModelで単純に公開されている場合は、モデルにINPCを実装できます。ただし、一般的に、ViewModelラップモデルは、モデルの複雑さを軽減するための独自のクラスです(バインディングには役立ちません)。この場合、INPCはViewModelに実装する必要があります。
ビューにバインドされているすべてのプロパティは、ViewModelにあります。したがって、それらはINotifyPropertyChangedインターフェイスを実装する必要があります。したがって、ビューはすべての変更を取得します。
[MVVM Lightツールキットを使用して、ViewModelBaseから継承させました。]
モデルはビジネスロジックを保持しますが、ビューとは関係ありません。したがって、INotifyPropertyChangedインターフェイスは必要ありません。
通常、ViewModelはINotifyPropertyChanged
を実装します。モデルは何でもかまいません(xmlファイル、データベース、またはオブジェクト)。モデルは、ビューモデルにデータを提供するために使用され、ビューモデルに伝達されます。
私は、ビューモデルがINotifyPropertyChange
を実装し、モデルが異なる「レベル」で通知を使用できると思います。
たとえば、いくつかのドキュメントサービスとドキュメントオブジェクトでは、ビューモデルがリッスンしてビューを再構築するためにリッスンするdocumentChangedイベントがあります。編集ビューモデルでは、ビューをサポートするためにドキュメントのプロパティのプロパティ変更があります。サービスが保存中のドキュメント(変更日、最終ユーザーなどの更新)で多くの処理を行う場合、Ipropertychangedイベントのオーバーロードを簡単に取得でき、documentchangedだけで十分です。
しかし、モデルでINotifyPropertyChange
を使用する場合、ビューで直接サブスクライブする代わりに、ビューモデルでリレーすることをお勧めします。その場合、モデルでイベントが変更されても、ビューモデルを変更するだけで、ビューは変更されません。
モデルでINotifyPropertyChange
インターフェイスを使用しています。実際には、モデルプロパティの変更は、UIまたは外部クライアントによってのみ起動される必要があります。
いくつかの利点と欠点に気付きました。
利点
Notifierはビジネスモデルにあります
欠点
モデルにはプロパティ(qty、rate、commission、totalfrieght)があります。 Totalfrieghtは、数量、レート、手数料の変更を使用して計算されます。
Dbから値をロードすると、総計計算が3回呼び出されます(数量、レート、手数料)。一度だけです。
レートの場合、数量がビジネスレイヤで割り当てられ、再び通知機能が呼び出されます。
おそらく基本クラスで、これを無効にするオプションがあるはずです。しかし、開発者はこれを忘れていました。
ビュー内のオブジェクトの参照が変更されたとします。正しい値を表示するために、すべてのプロパティを更新するように通知するにはどうすればよいですか?ビューのOnPropertyChanged
をすべてのオブジェクトのプロパティに対して呼び出すことは、私の観点ではごみです。
そのため、プロパティの値が変更されたときにオブジェクト自体に通知するようにオブジェクトを設定し、私のビューでは_Object.Property1
_、_Object.Property2
_などのバインディングを使用しています。そのようにして、ビューで現在保持されているオブジェクトを変更したい場合は、OnPropertyChanged("Object")
を実行します。
オブジェクトのロード中に何百もの通知を避けるために、オブジェクトのOnPropertyChanged
からチェックされ、何もしないロード中にtrueに設定するプライベートブールインジケータがあります。