web-dev-qa-db-ja.com

MVVMでは、ViewModelまたはModelはINotifyPropertyChangedを実装する必要がありますか?

私が経験したほとんどのMVVMの例では、ModelがINotifyPropertyChangedを実装していましたが、 Josh SmithのCommandSinkの例ViewModel INotifyPropertyChangedを実装します。

私はまだ認知的にMVVMの概念をまとめているので、次の場合にはわかりません:

  • commandSinkを機能させるには、ViewModelにINotifyPropertyChangedを配置する必要があります
  • これは単なる規範の異常であり、実際には問題ではありません
  • モデルには常にINotifyPropertyChangedを実装させる必要がありますが、これはコード例からアプリケーションに開発された場合に修正される単なる間違いです

あなたが取り組んできたMVVMプロジェクトで他の人はどのような経験をしましたか?

155
Edward Tanguay

私はまったく反対だと思います、私は常にINotifyPropertyChangedをViewModelに置きます-あなたは本当にINotifyPropertyChangedのようなかなりWPF固有の機能でモデルを汚染したくありません。 ViewModelに座ってください。

他の人も意見が違うと思いますが、それが私のやり方です。

100
Steven Robbins

モデルがINotifyPropertyChangedを実装すべきではないという概念には強く反対します。このインターフェイスはUI固有ではありません!変更を通知するだけです。実際、WPFはこれを使用して変更を識別しますが、それがUIインターフェイスであることを意味するわけではありません。これを次のコメントと比較します。「タイヤはカーアクセサリーです」。確かにありますが、自転車、バスなども使用します。 要約すると、そのインターフェースをUIのものとして受け取らないでください。

そうは言っても、必ずしもモデルが通知を提供するべきだと思うとは限りません。 実際、経験則として、必要でない限り、モデルはこのインターフェイスを実装すべきではありません。サーバーデータがクライアントアプリにプッシュされないほとんどの場合、モデルは古くなる可能性があります。しかし、金融市場のデータを聞いていると、モデルがインターフェイスを実装できない理由がわかりません。例として、特定の値の買値または売値を受け取ったときにアラートを発行するサービス(電子メールなど)または注文するサービスなどの非UIロジックがある場合はどうなりますか?これは、クリーンなソリューションになる可能性があります。

しかし、物事を達成するさまざまな方法がありますが、私は常に単純さを支持し、冗長性を避けることを主張します。

何が良いですか?コレクションでのイベントまたはプロパティの変更をビューモデルで定義し、それをモデルに伝播するか、ビューが本質的にモデルを更新する(ビューモデルを介して)か?

これができない、またはthat」と主張している人を見かけたら、それは彼らが何について話しているのかわからないサインです。

それは本当にあなたのケースに依存し、実際MVVMは多くの問題を抱えたフレームワークであり、MVVMの一般的な実装はまだ見ていません。

MVVMの多くのフレーバーと、主に他の開発者によって提供される一般的な問題に対するいくつかの解決策を説明する時間があればいいのですが、また別の機会にやらなければならないと思います。

134
Paulo Sousa

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プロジェクトの優れた開始テンプレートになるはずです。

28
Soni Ali

MVVMの名前は非常に不適切であり、ViewModelをViewModelと呼ぶと、多くの人が適切に設計されたアーキテクチャの重要な機能を見逃してしまいます。

View-ModelをDataControllerのように考え、DataControllerがデータに触れる唯一のアイテムであるアーキテクチャを実装する場合、データに直接触れることはありませんが、常にDataControllerを使用します。 DataControllerはUIにとっては便利ですが、必ずしもUIだけではありません。ビジネスレイヤー、UIレイヤーなど用です。

DataModel -------- DataController ------ View
                  /
Business --------/

このようなモデルになります。ビジネスでさえ、ViewModelを使用してデータにのみアクセスする必要があります。その後、あなたの難問は消え去ります。

11
Rhyous

モデルの実装方法によって異なります。私の会社は、LhotkaのCSLAオブジェクトと同様のビジネスオブジェクトを使用し、ビジネスモデル全体でINotifyPropertyChangedを広範囲に使用しています。

検証エンジンは、このメカニズムを通じてプロパティが変更されることを通知されることに大きく依存しており、非常にうまく機能します。明らかに、変更の通知が操作にとってそれほど重要ではないビジネスオブジェクト以外の異なる実装を使用している場合、ビジネスモデルの変更を検出する他の方法があるかもしれません。

また、必要に応じてモデルからの変更を伝播するビューモデルもありますが、ビューモデル自体は、基礎となるモデルの変更をリッスンしています。

8
Steve Mitcham

Pauloの答えに同意します。ModelsにINotifyPropertyChangedを実装することは完全に受け入れられ、Microsoftによっても提案されています-

通常、モデルはビューへのバインドを容易にする機能を実装します。これは通常、INotifyPropertyChangedおよびINotifyCollectionChangedインターフェイスを介したプロパティおよびコレクションの変更通知をサポートすることを意味します。オブジェクトのコレクションを表すモデルクラスは通常、ObservableCollection<T>クラス。INotifyCollectionChangedインターフェイスの実装を提供します。

そのタイプの実装が必要かどうかはあなた次第ですが、覚えておいてください-

モデルクラスが必要なインターフェイスを実装していない場合はどうなりますか?

場合によっては、INotifyPropertyChangedINotifyCollectionChangedIDataErrorInfo、またはINotifyDataErrorInfoインターフェイスを実装しないモデルオブジェクトを使用する必要があります。これらの場合、ビューモデルはモデルオブジェクトをラップし、必要なプロパティをビューに公開する必要があります。これらのプロパティの値は、モデルオブジェクトによって直接提供されます。ビューモデルは、公開するプロパティに必要なインターフェイスを実装するため、ビューはそれらに簡単にデータバインドできます。

から取得- http://msdn.Microsoft.com/en-us/library/gg405484(PandP.40).aspx

モデルにINotifyPropertyChangedを実装していないプロジェクトで働いてきましたが、これが原因で多くの問題に直面しました。プロパティの不必要な複製がVMで必要であり、同時に、BL/DLに渡す前に、基礎となるオブジェクトを更新された値で更新する必要がありました。

モデルオブジェクトのコレクション(編集可能なグリッドやリストなど)や複雑なモデルを扱う必要がある場合は、特に問題に直面します。モデルオブジェクトは自動的に更新されず、VMですべてを管理する必要があります。

4
akjoshi

しかし、(このプレゼンテーションのように リンクテキスト )モデルはサービスであり、アプリケーションにオンラインでデータを提供し、イベントを使用して新しいデータが到着したか、データが変更されたという通知を実装する必要があります...

3
Andrey Khataev

MV-VMに固執したい場合、答えは非常に明確だと思います。

参照: http://msdn.Microsoft.com/en-us/library/gg405484(v = PandP.40).aspx

MVVMパターンでは、ビューはUIとUIロジックをカプセル化し、ビューモデルはプレゼンテーションロジックと状態をカプセル化し、モデルはビジネスロジックとデータをカプセル化します。

「ビューは、データバインディング、コマンド、変更通知イベントを介してビューモデルと対話します。ビューモデルは、モデルの更新をクエリ、監視、調整し、ビューでの表示に必要なデータを変換、検証、集計します。」

3
John D

私はあなたのViewModelで言うでしょう。モデルはUIに依存しないため、モデルの一部ではありません。モデルは「ビジネスにとらわれないものすべて」でなければなりません

2
Steve Dunn

モデルではなくビューモデルでINotifyPropertyChangeを使用するだけで、

通常、モデルはIDataErrorInfoを使用して検証エラーを処理するため、ViewModelを保持するだけで、MVVMを使用できます。

1
Adam

すべてはユースケースに依存すると思います。

多数のプロパティを持つ単純なモデルがある場合、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プロパティの値が変更される可能性があることを伝えることができます」。

1
dzendras

モデルがViewModelで単純に公開されている場合は、モデルにINPCを実装できます。ただし、一般的に、ViewModelラップモデルは、モデルの複雑さを軽減するための独自のクラスです(バインディングには役立ちません)。この場合、INPCはViewModelに実装する必要があります。

0

ビューにバインドされているすべてのプロパティは、ViewModelにあります。したがって、それらはINotifyPropertyChangedインターフェイスを実装する必要があります。したがって、ビューはすべての変更を取得します。

[MVVM Lightツールキットを使用して、ViewModelBaseから継承させました。]

モデルはビジネスロジックを保持しますが、ビューとは関係ありません。したがって、INotifyPropertyChangedインターフェイスは必要ありません。

0
donotbefake

通常、ViewModelはINotifyPropertyChangedを実装します。モデルは何でもかまいません(xmlファイル、データベース、またはオブジェクト)。モデルは、ビューモデルにデータを提供するために使用され、ビューモデルに伝達されます。

こちらを参照

0
Syed

私は、ビューモデルがINotifyPropertyChangeを実装し、モデルが異なる「レベル」で通知を使用できると思います。

たとえば、いくつかのドキュメントサービスとドキュメントオブジェクトでは、ビューモデルがリッスンしてビューを再構築するためにリッスンするdocumentChangedイベントがあります。編集ビューモデルでは、ビューをサポートするためにドキュメントのプロパティのプロパティ変更があります。サービスが保存中のドキュメント(変更日、最終ユーザーなどの更新)で多くの処理を行う場合、Ipropertychangedイベントのオーバーロードを簡単に取得でき、documentchangedだけで十分です。

しかし、モデルでINotifyPropertyChangeを使用する場合、ビューで直接サブスクライブする代わりに、ビューモデルでリレーすることをお勧めします。その場合、モデルでイベントが変更されても、ビューモデルを変更するだけで、ビューは変更されません。

0
Bram

モデルでINotifyPropertyChangeインターフェイスを使用しています。実際には、モデルプロパティの変更は、UIまたは外部クライアントによってのみ起動される必要があります。

いくつかの利点と欠点に気付きました。

利点

Notifierはビジネスモデルにあります

  1. ドメイン駆動ごとに、それは正しいです。いつレイズするか、しないのかを決定する必要があります。

欠点

モデルにはプロパティ(qty、rate、commission、totalfrieght)があります。 Totalfrieghtは、数量、レート、手数料の変更を使用して計算されます。

  1. Dbから値をロードすると、総計計算が3回呼び出されます(数量、レート、手数料)。一度だけです。

  2. レートの場合、数量がビジネスレイヤで割り当てられ、再び通知機能が呼び出されます。

  3. おそらく基本クラスで、これを無効にするオプションがあるはずです。しかし、開発者はこれを忘れていました。

0
Anand Kumar

ビュー内のオブジェクトの参照が変更されたとします。正しい値を表示するために、すべてのプロパティを更新するように通知するにはどうすればよいですか?ビューのOnPropertyChangedをすべてのオブジェクトのプロパティに対して呼び出すことは、私の観点ではごみです。

そのため、プロパティの値が変更されたときにオブジェクト自体に通知するようにオブジェクトを設定し、私のビューでは_Object.Property1_、_Object.Property2_などのバインディングを使用しています。そのようにして、ビューで現在保持されているオブジェクトを変更したい場合は、OnPropertyChanged("Object")を実行します。

オブジェクトのロード中に何百もの通知を避けるために、オブジェクトのOnPropertyChangedからチェックされ、何もしないロード中にtrueに設定するプライベートブールインジケータがあります。

0
Dummy01