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


165

私がこれまでに取り組んだほとんどのMVVMの例にはModel実装 INotifyPropertyChangedがありましたが、Josh SmithのCommandSinkの例で はViewModelが実装されていINotifyPropertyChangedます。

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

  • あなたは配置する必要がありINotifyPropertyChanged得るためのViewModelにCommandSink仕事に
  • これは単なる標準の逸脱であり、それは本当に問題ではありません
  • あなたは常にモデルを実装する必要があり、INotifyPropertyChangedこれは単なるコードミスからアプリケーションに開発された場合に修正される間違いです

あなたが取り組んできたMVVMプロジェクトに関する他の経験は何ですか?


4
INPCを実装する場合は、github.com / Fody / PropertyChangedを試してみてください。これにより、数週間入力する手間が省けます。
CADは16

回答:


104

私はまったく反対だと思います、私はいつもINotifyPropertyChanged自分のViewModelを使用します-のようなかなりWPF固有の機能でモデルを汚染したくないのでINotifyPropertyChanged、それらはViewModelに配置する必要があります。

私は他の人が反対するだろうと確信していますが、それが私の仕事のやり方です。


84
モデルのプロパティが変更された場合はどうしますか?どういうわけかそれをビューモデルに取得する必要があります。正直なところ、私は今、この難問を扱っています。
Roger Lipscombe、2010年

4
PrismコードのEventAggregatorは、モデルのINotifyPropertyChangedに代わる優れた方法であり、カスタムプロパティが変更されたイベントタイプがあります。そのプロジェクトのイベントコードは、バックグラウンドスレッドとUIスレッド間のイベントの転送をサポートしています。
スティーブミッチャム2010

51
INotifyProperyChangedはWPF固有ではなく、System.ComponentModel名前空間にあります。WinFormsアプリケーションで使用しています。また、INotifyPropertyChangedは2.0以降.Netにあり、WPFは3.0以降にのみ存在します
benPearce

40
私はINotifyPropertyChangedをMODELとVIEWMODELの両方に配置するのが好きです。これをしない理由は考えられません。VIEWに通知するために使用され、VIEWMODELに変更があったように、VIEWMODELに影響を与えるバックグラウンドの変更がMODEで発生したことをVIEWMODELに通知するエレガントな方法です。
ScottCher

6
@Steve-モデルのプロパティが変更されたことをViewModelに通知することについて、INotifyPropertyChangedは「viewmodelがフックできるイベント」として正常に機能しているようです。使ってみませんか?
skybluecodeflier 2011年

146

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

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

ただし、物事を達成する方法はいくつかありますが、私は常に単純さを優先し、冗長性を避けることを主張します。

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

肝心なのは、「これができない、またはできない誰かが言っているのを見るときはいつでも、彼らが何を話しているのか分からないという兆候です。

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

MVVMの多くのフレーバーと一般的な問題のいくつかの解決策を説明する時間がもっとあればいいと思います-ほとんどが他の開発者によって提供されますが、私は別の機会にそれをしなければならないでしょう。


7
このように考えてください。あなたが開発者としてモデルで.dllを使用する場合、INotifyPropertyChangedをサポートするようにモデルを書き直すことはありません。
Lee Treveil、2011

2
あなたに強く同意します。私と同じように、公式のMVVMドキュメント< msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx >(モデルセクション)が私たちに同意することを知って喜んでいるかもしれません。:-)
Noldorin、2009

「しかし、これは物事を達成するためのさまざまな方法ですが、私は常に単純さを優先し、冗長性を避けることを主張します。」とても重要です。
バスティアンヴァンダム

1
INotifyPropertyChangedSystem.ComponentModelコンポーネントとコントロールの実行時および設計時の動作」のための名前空間の一部です。モデルでは使用せ INotifyPropertyChangedず、ViewModelでのみ使用してください。ドキュメントへのリンク:docs.microsoft.com/en-us/dotnet/api/system.componentmodel
Igor Popov

1
昔の投稿ですが、MVVMを使用して新しいプロジェクトを開始するときは、よく戻ってきます。私は最近、単一責任の原則をより厳密に実施し始めました。モデルは一つの責任を持つことです。モデルになること。INotifyPropertyChangedをモデルに追加するとすぐに、単一責任の原則に従っていません。ViewModelが存在する理由は、モデルをモデルにして、モデルに単一の責任を持たせるためです。
Rhyous

30

MV-VMでは、常にViewModel(モデルは常にではない)が実装されます INotifyPropertyChanged

http://blogs.msdn.com/llobo/archive/2009/05/01/download-mv-vm-project-template-toolkit.aspxからMV-VMプロジェクトテンプレート/ツールキットを確認してください。それはDelegateCommandコマンドを使用し、MV-VMプロジェクトの優れた開始テンプレートになるはずです。


その最初の文は、他の答えの意見をかなりよくまとめています、imo。=>投票する!
j00hi

13

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

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

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

このようなモデルになります。ビジネスでさえ、ViewModelを使用してデータに触れるだけです。その後、あなたの難問はちょうど消えます。


3
DataControllerが変更したときにのみデータが変更される場合、これはすばらしいことです。データがデータベースまたは変更の別の手段を提供できる他のデータストアからのものである場合、VIEWMODEL(パターンのDataController)とVIEWにそれが発生したときに通知する方法が必要になる場合があります。DataControllerを使用してポーリングするか、外部プロセスからDataModelにプッシュして、DataModelが変更通知をDataControllerに送信できるようにします。
ScottCher

4
あなたはまさに正しいです。デザインパターンは非常に高いレベルです。ほとんどの場合、設計パターンは正しいことを行うように導きますが、時々、間違った方向に向きを変えます。デザインパターンの外にあるため、正しいことをしないでください。
Rhyous、

また、DataControllerがデータモデルを制御し、更新するようにプッシュすることもできます。
Rhyous

また、MVVMのモデルは、UI(DTOなど)の必要に応じて固有に保つ必要があります。そのため、DBまたは複雑なビジネスロジックは別のレイヤーで発生し、ビューモデルを介して大まかなデータが提供される必要があります。
コードネームJack

9

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

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

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


3
モデルのOnPropertyChangedをViewModelのOnPropertyChangedに正確にどのように伝播しますか?ViewModelがModelとは異なるプロパティ名を持っていると問題が発生します。その場合は、名前から名前へのマッピングが必要になります。
Martin Konicek、2009

それは本当に洗練されたものではなく、イベントを転送するだけです。名前が異なる場合は、ルックアップテーブルを使用できます。変更が1対1のマッピングでない場合は、イベントをフックして、ハンドラーで必要なイベントを発生させることができます。
スティーブミッチャム

6

私はパウロの答えに同意します、INotifyPropertyChangedモデルでの実装は完全に受け入れ可能であり、マイクロソフトによって提案さえされています-

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

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

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

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

取得元-http ://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx

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

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


3

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


3

MV-VMを使用したい場合、その答えは非常に明確だと思います。

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

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

「ビューは、データバインディング、コマンド、および変更通知イベントを介してビューモデルと対話します。ビューモデルは、モデルの更新を照会、監視、および調整し、ビューに表示するために必要に応じてデータを変換、検証、および集計します。」


4
引用は解釈に対して開かれています。私はあなたの答えは明確にするために、あなたの解釈を加えるべきだと思います:-)
セーレンBoisen

@John D:その記事は、MVVMの1つの解釈とそれを実装する方法を提供するだけで、MVVMを定義していません。
akjoshi

さらに、記事全体を読むと、次のようにModelクラスが定義されています。「通常、モデルはビューに簡単にバインドできる機能を実装しています。これは通常、INotifyPropertyChangedおよびINotifyCollectionChangedインターフェースを介してプロパティとコレクションの変更通知をサポートすることを意味します。オブジェクトのコレクションを表すモデルクラスは、通常、ObservableCollection <T>クラスから派生します。これは、INotifyCollectionChangedインターフェイスの実装を提供します。」
akjoshi

2

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


2

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


1

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

私はいくつかの利点と欠点に気づきました:

メリット

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

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

短所

モデルにはプロパティ(数量、レート、コミッション、トータルフリート)があります。Totalfrieghtは、数量、レート、手数料の変更を使用して計算されます。

  1. dbから値をロードすると、合計料金計算が3回呼び出されます(数量、レート、手数料)。それは一度であるべきです。

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

  3. これを無効にするオプションが、おそらく基本クラスにあるはずです。ただし、開発者はこれを行うのを忘れる可能性があります。


あなたが挙げたすべての欠点のため、INPCをモデルに実装するのは比較的大きなWPFプロジェクトで間違った決定であると判断しました。それらは永続層のみを処理する必要があります。検証、変更通知、計算されたプロパティなど、他のすべてのものはViewModelで処理する必要があります。ViewModelでモデルプロパティを繰り返すことが常にDRYの原則に違反するとは限らないことを理解しました。
try2fly.b4ucry

1

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

プロパティのロードを持つ単純なモデルがある場合、INPCを実装することができます。簡単に言うと、このモデルはPOCOのように見えますます。

モデルがより複雑でインタラクティブなモデルドメイン(モデルを参照するモデル、他のモデルのイベントにサブスクライブする)に存在する場合、INPCとしてモデルイベントを実装することは悪夢です。

他のいくつかのモデルと連携する必要があるモデルエンティティの位置に自分を置きます。購読するさまざまなイベントがあります。それらはすべてINPCとして実装されています。あなたが持っているそれらのイベントハンドラを想像してみてください。if節やswitch節の巨大なカスケード。

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

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

モデルは通常IDataErrorInfo、検証エラーを処理するためにを使用するので、ViewModelをそのままにしておけば、MVVMの道を進むことができます。


1
複数のプロパティを持つモデルはどうですか?VMでコードを繰り返しています。
ルイス・

0

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

だから私がやっていることは、プロパティの値が変更されたときにオブジェクト自体に誰かに通知させることです、そして私の見解ではObject.Property1Object.Property2などのバインディングを使用しています。このようにして、ビューに現在保持されているオブジェクトを変更したいだけの場合は、それを行いますOnPropertyChanged("Object")

オブジェクトのロード中の何百もの通知を回避するために、私はロード中にtrueに設定するプライベートブールインジケーターを持っています。これはオブジェクトからチェックされ、OnPropertyChanged何もしません。


0

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

こちらをご覧ください


1
ええと。モデルをXMLファイルまたはデータベースにすることはできません。そして、モデルはデータを与えるために使用されていません。それ以外の場合は、「モデル」ではなく「データ」と呼ぶ必要があります。モデルはデータを記述するために使用されます。かなり自明ですよね?:)
タラス

1
より良い答えがある場合は、共有してください!私たちは皆、知識を共有し、競争しないためにここにいます
Adam

0

imho私はviewmodelが実装INotifyPropertyChangeし、モデルが別の「レベル」で通知を使用できると思います。

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

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


0

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

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

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

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