INotifyPropertyChanged
(INPC)は、モデルがViewModelでもない(つまり、「モデル」がない)場合を除いて、モデルに含めることはできません。INPCはビューモデルにのみ存在する必要があります。
モデルはビューモデルについて何も知らないはずなので、モデルと通信することはできません。ビューモデルのみがモデルと通信できます。
UIの観点からは、ビューモデルのみがデータを処理します。したがって、モデルを「読み取り専用」にする場合は、ビューモデルに実装しないでください。
バインドはビューモデルを使用して行われます。この場合、ディクショナリを使用しないでください(バインドするためにディクショナリをラップするコードを記述したい場合を除く)。ディクショナリがモデルにある場合は、ビューモデルでそれを「ラップ」する必要があります。コレクションの周りに監視可能なラッパーを作成するのは非常に簡単です。おそらく、ビューモデルはキーと値のペアを処理しません。UIが処理できる(そしてバインドできる)フラットなものを処理する必要があります。
更新:
データバインディング用にINPCが導入されました。ビューを特定の具象クラスから分離するため、INPCについてのみ知る必要があります(分離の方向に注意してください)。MVVMの場合、これはビューをビューモデルから切り離します。PMの場合、これはビューをプレゼンターから切り離す可能性があります。MVCの場合、これはビューをコントローラーから切り離す可能性があります。MVPの場合、これはプレゼンターからの眺め。
データバインディングは、データをUI要素にバインドする手法です。データソースをターゲットにバインドして、ターゲットが適切と思われる方法でデータを要求したり、ソースが適切と思われる方法でデータをプッシュしたりできるようにします(バインドのタイプに応じて、一方向または静的である可能性があり、方法が制限されます)多くの場合、get / pushが発生する可能性があります)。
データソースとターゲットの間の分離された関係の必要な性質により、データバインディングはUIの問題ではなく、データバインディングはどこにでも適用できると人々が信じる場合があります。つまり、データバインディングの実装はUIから完全に切り離されています。これは一般的に間違いです。データバインディングは、ビューを特定のクラスの特定の知識から切り離します(これは基本的な階層化とサイクルの回避であり、ここでは説明しません)。ただし、ビューをデータソースから完全に分離するわけではありません。バインディングはデータソースなしでは発生しません-そこにはまだある程度のカップリングがあり、緩和されたのはコンパイル時のカップリングだけです(テスト、柔軟性、堅牢性などの支援ですが、本番環境では実行時に存在する必要があります。つまり、INPC実装を実行時にUI要素にバインドせずにテストできるという事実は、UIフレームワークに依存していないことを意味するわけではありません。ビューがまだデータソースに緩く結合されているという事実は、この関係の唯一の結合ではありません。データソースは、UIフレームワークを介してビューに緩く結合されています(緩くはないにしても)。
すべてのUIフレームワークには、UI要素へのアクセスと変更をメインスレッドまたはUIスレッドで実行する必要があるという制限があります。(少なくともWindowsでは、他のプラットフォームで発生する可能性があります。私は他のプラットフォームに精通していません)。データバインディングを使用すると、ソースは間接的にコントロールにバインドされ、データの変更によって1つ以上のUI要素が直接変更されます(フレームワークに応じて、仲介者を使用できます。WinRTの値コンバーターと同様ですが、データの変換または変換を担当します)。つまり、データソースは、UIにバインドされていること、およびバインドされているUIフレームワークのタイプについての深い知識を持っている必要があります。UIフレームワークへのこの緊密な結合は、データソースを(まだ緩く)UIに明確に結合します。
これは、INPCの特定の実装が実際に1つだけのUIフレームワークにバインドされていることを意味します。そのオブジェクトはもはやどこでも使用できません(明らかにどこでも理想的であり、すべてのシナリオで何かを機能させることは不可能なことがよくあります。ここでのポイントは、1つまたは2つ以上のシナリオでの高い凝集度です)。たとえば、INPCの実装がマルチスレッド環境で使用されている場合、プロパティ通知を送信する前に、データをUIスレッドに「マーシャリング」する必要があります。WinFormsでは、それControl.BeginInvoke
は、WPFとSilverlightでは経由System.Windows.Threading.Dispatcher
です。WinRTでは、それは経由Windows.UI.CoreDispatcher
です。すべての場合において、INPC実装は1つのUIフレームワークに直接結合する必要があります。Silverlightの場合、これは「デスクトップ」のいずれかに直接結合します。Dispatcher
またはWindowsPhone Dispatcher
。
品質メトリックには、凝集性などの概念が含まれます。凝集度は、2つのコード単位がどれほど強く関連しているかを示す尺度です。UI以外で使用されるINPCの実装は、その1つの特定のUIフレームワークをサポートするために必要なすべてのインフラストラクチャの性質により、UIの外部で使用できる可能性はありますが、すべてのUIフレームワークに関連するコードは使用されません。つまり、UIから完全に切り離すには、あまりにも多くの責任を負います。はい、どこでもINPCを実装するオブジェクトを使用でき、PropertyChanged
イベントを使用することはできませんが、その場合、結合率は低くなります(悪いと見なされます)。
モデルにINPCを実装し、そのモデルをUIとWCFまたはWebサービスのバックエンドの両方で使用したい場合は、使用できないか、バックエンドがUIフレームワークを参照する必要があります。そのモデルを別のタイプのUIで使用したい場合、そのINPCの実装は特定のUIフレームワークに依存しているため、使用できませんでした。別の「モデル」を作成する必要があります。その時点で、それは明らかに「ビューモデル」です。
INPC自体は特定のUIフレームワークにバインドされていません(バインドされるべきではありません)。これは、INPCがどこでも使用できるという誤解につながります。 はい、高レベルの名前空間への結合がないということは、それが可能であることを意味しますが、INPCの圧倒的な使用法は、ターゲットがUIの場合です。真の「バインディング」としてUIを含まないINPCの他の使用法に挑戦したいと思います。他のツールと同様に、それを誤用して有用な結果を得ることができます。INPCは、データの投影、データの変換などに使用できます。しかし、これらはINPCの誤用であり、この質問の焦点から外れていると思います...