none
WPF MVVMにおけるModelのViewModel, Viewへの対応について RRS feed

  • 質問

  • MVVMについて初歩的な質問があります。

    使用している環境は下記のとおりです。

    • WPF 4.0
    • Visual Studio 2013 Professional
    • MVVMフレームワーク Livet使用検討中

    ModelからViewModel、Viewへと状態の変化を通知するにはプロパティに対してPropertyChangedイベント発行の追加や、ObservableCollection型のコレクションを使用する必要がありますが、これらはModelの深い部分にも使用していくものなのでしょうか?

    (特に、すでに既存のModelがある場合など)

    それとも、Modelの既存のプロパティの変化をViewに通知可能な形にするためPropertyChangedイベントの発行を行うなどのModelとViewのつなぎを行うのがViewModelの役割となるのでしょうか?

    あるいは、ModelがViewModelの参照を持たないようにするにはModel側にもPropertyChangedなどの記述が必要になるため、Model側の上層でViewModelを意識した部分などを用意するものなのでしょうか?

    web上のサンプルはどれもModelの階層が浅く、ViewModel == Modelぐらいのわかりやすさとなっているため、ModelのどのあたりまでViewを意識した設計にするものなのか検討がつきづらいです。

    実際WPFでMVVMを意識して作成される際ModelがどのレベルまでViewを意識したコードとなっているのか、今までの経験などから教えていただけると助かります。

    回答よろしくお願いします。

    2015年3月31日 4:39

回答

  • こんにちは。

    これについては色々な意見がありそうです。

    私はご質問中の以下を意識することが多いです。

    それとも、Modelの既存のプロパティの変化をViewに通知可能な形にするためPropertyChangedイベントの発行を行うなどのModelとViewのつなぎを行うのがViewModelの役割となるのでしょうか?

    既存がWinFormだった場合、Form.csなどのプレゼンテーションロジックの実装はほぼViewModelに移行しています。
    実質ModelとViewの繋ぎを行い、レイアウトや文言などのみをViewにしてます。

    ですのでModelはビジネスロジックのみに集中しViewを意識しなくて良いと思います。

    ただ、これは私の意見ですので。

    例えばMVVMフレームワークのLivetではINotifyPropertyChangedを実装したModelオブジェクトが存在したと思います。
    あとは汎用性や保守性などをどこまで考慮するか、でしょうか・・・

    • 回答としてマーク h--s 2015年3月31日 5:46
    • 回答としてマークされていない h--s 2015年3月31日 5:55
    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 5:05
    モデレータ
  • この辺りは様々な考えがあるので最適解をお示しすることはできませんが、私は View で Model を扱いやすいよう、InofityPropertyChanged を実装した方が便利だと考えてます。

    以下で公開しているサンプルでは、Model にINotifyPropertyChanged を実装してますが (実際は Livet のNotificationObjectを継承)、現実の開発でも View にバインドする Model は全て INotifyPropertyChanged を実装しています。

    http://d.hatena.ne.jp/hilapon/20150319/1426743980

    ちなみに現在、Forms から WPF への移行という二つのアーキテクトが混在する状況下で、Model を WPF・Forms の両方の画面で使っています。INotifyPropertyChanged を実装していても、何の問題も発生していません。MVVM はあくまで「アプリケーションアーキテクチャパターン」なので、実装に縛られることなく、ある程度遵守できていれば、まあいいかなとくらい軽く考えています。

    ぜひ 「フォーラムでご質問頂くにあたっての注意点」 もご覧ください https://social.msdn.microsoft.com/Forums/ja-JP/ca9ecfb7-4407-4fcb-b8bd-207d68257e68?forum=announceja

    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 7:06
    モデレータ
  • View, ViewModel, Modelはあくまで概念であって、それぞれ1つのオブジェクトで表すのは無理があると思います。ViewやViewModelは1つのオブジェクトで構成しやすく、実際、そのなっている例がほとんどだと思いますので、Modelもそう考えがちですが、Modelは基本的に2つに分けて考えた方が良いように私は思います。よって、私がよくやるのは以下のパターンです。

    View <-> VeiwModel <-> UIObject <-> Model

    ここでModelはプロパティのみしかないクラスです。UIObjectはModelをラップし、INotifyPropertyChangedを実装しています。これをObservableCollectionでくるんでViewModelでプロパティとして公開し、Viewがバインドします。また、ViewModelもINotifyPropertyChangedを実装し、前述のObservableCollection以外のプロパティも公開します。例えば、この画面にエラーがあるかどうかを表すプロパティです。

    >Modelが自発的に内部で変化してその変化をViewModelに伝える場合はどのようにするのでしょうか?

    これは私はイベントでやっています。UIObjectのイベントです。ただ、イベントを使うには注意が必要で、必要に応じて弱い参照を行わないとメモリーリークします。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 7:06
    モデレータ

すべての返信

  • 基本的にModelはViewを全く知らなくていいはずです。Modelを直接Viewにバインドしていませんか?

    ViewにバインドするのはあくまでViewModelです。ViewModelで必要な値をModelからViewModelにコピーしてください。


    2015年3月31日 4:54
  • こんにちは。

    これについては色々な意見がありそうです。

    私はご質問中の以下を意識することが多いです。

    それとも、Modelの既存のプロパティの変化をViewに通知可能な形にするためPropertyChangedイベントの発行を行うなどのModelとViewのつなぎを行うのがViewModelの役割となるのでしょうか?

    既存がWinFormだった場合、Form.csなどのプレゼンテーションロジックの実装はほぼViewModelに移行しています。
    実質ModelとViewの繋ぎを行い、レイアウトや文言などのみをViewにしてます。

    ですのでModelはビジネスロジックのみに集中しViewを意識しなくて良いと思います。

    ただ、これは私の意見ですので。

    例えばMVVMフレームワークのLivetではINotifyPropertyChangedを実装したModelオブジェクトが存在したと思います。
    あとは汎用性や保守性などをどこまで考慮するか、でしょうか・・・

    • 回答としてマーク h--s 2015年3月31日 5:46
    • 回答としてマークされていない h--s 2015年3月31日 5:55
    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 5:05
    モデレータ
  • ViewModelで必要な値をModelからViewModelにコピーしてください。

    Modelが自発的に内部で変化してその変化をViewModelに伝える場合はどのようにするのでしょうか?

    ModelがObserverパターンなどの形でViewModelの参照を持つのでしょうか?

    2015年3月31日 5:06
  • Modelが自発的に内部で変化してその変化をViewModelに伝える場合はどのようにするのでしょうか?

    それは、WinFormでも同じではないでしょうか。
    ViewModelが定期的にModelを監視するのか、それともModelからイベントを発行してViewModelのコールバックを呼び出すのか。
    同期処理でパラメータを返すのか、など。

    ビジネスロジックの状態変化をどうやってフォームに反映するのか、と同じ考えで良い気もします。
    ViewModelへの反映は。

    2015年3月31日 5:22
    モデレータ
  • Tak1waさんの場合は、先ほどおっしゃったようにWinFormの内の処理がそのままViewModelに移行したという形なんですね。

    参考になります。

    この質問を投げた理由の1つとして言及されたとおり、Livetでは変更通知をもつModelの基本クラスが存在し、ViewModelがModelからの変更イベントを素通りして簡単にViewへ投げることができる仕組みが存在しているためです。

    このため、Modelの中身もViewやViewModelを意識した形にしたほうがよいのかと混乱してしまいました。

    また、ModelがViewModelの参照を持っていいのかどうなのか、判断がついていないという点もあります。(Modelから変更イベントを投げる形にすると、ViewModelとModelも疎結合になりますが、ModelにViewModelの要素が侵食していきます)

    できるだけModelはそのままにしておきたい、使いまわせるようにしておきたいため、Tak1waさんを参考にViewModel層をやや膨らまさせて表示要素・処理をまとめるようにしようと思います。

    2015年3月31日 5:46
  • 結局は方針を最初に決めてそれに従っていけば良いです。

    Modelに通知を実装してViewにバインドさせたほうが楽ですし、
    ビジネスロジックやエンティティの構造がUIに似ているほど、その実装でも問題が無いことがほとんどではないでしょうか。(たぶん)

    なのでアプリケーションの要件や規模に応じて、臨機応変に方針を決める必要があり、ベストプラクティスは無いと思います。

    ※WPFで問題になるのはViewの参照をViewModel以下で持ってしまうことによるメモリリークが一番だと個人的には思いますので
    Viewが分離されていればなんでもいいかなと正直思ってはおります。

    2015年3月31日 6:41
    モデレータ
  • この辺りは様々な考えがあるので最適解をお示しすることはできませんが、私は View で Model を扱いやすいよう、InofityPropertyChanged を実装した方が便利だと考えてます。

    以下で公開しているサンプルでは、Model にINotifyPropertyChanged を実装してますが (実際は Livet のNotificationObjectを継承)、現実の開発でも View にバインドする Model は全て INotifyPropertyChanged を実装しています。

    http://d.hatena.ne.jp/hilapon/20150319/1426743980

    ちなみに現在、Forms から WPF への移行という二つのアーキテクトが混在する状況下で、Model を WPF・Forms の両方の画面で使っています。INotifyPropertyChanged を実装していても、何の問題も発生していません。MVVM はあくまで「アプリケーションアーキテクチャパターン」なので、実装に縛られることなく、ある程度遵守できていれば、まあいいかなとくらい軽く考えています。

    ぜひ 「フォーラムでご質問頂くにあたっての注意点」 もご覧ください https://social.msdn.microsoft.com/Forums/ja-JP/ca9ecfb7-4407-4fcb-b8bd-207d68257e68?forum=announceja

    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 7:06
    モデレータ
  • View, ViewModel, Modelはあくまで概念であって、それぞれ1つのオブジェクトで表すのは無理があると思います。ViewやViewModelは1つのオブジェクトで構成しやすく、実際、そのなっている例がほとんどだと思いますので、Modelもそう考えがちですが、Modelは基本的に2つに分けて考えた方が良いように私は思います。よって、私がよくやるのは以下のパターンです。

    View <-> VeiwModel <-> UIObject <-> Model

    ここでModelはプロパティのみしかないクラスです。UIObjectはModelをラップし、INotifyPropertyChangedを実装しています。これをObservableCollectionでくるんでViewModelでプロパティとして公開し、Viewがバインドします。また、ViewModelもINotifyPropertyChangedを実装し、前述のObservableCollection以外のプロパティも公開します。例えば、この画面にエラーがあるかどうかを表すプロパティです。

    >Modelが自発的に内部で変化してその変化をViewModelに伝える場合はどのようにするのでしょうか?

    これは私はイベントでやっています。UIObjectのイベントです。ただ、イベントを使うには注意が必要で、必要に応じて弱い参照を行わないとメモリーリークします。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    • 回答としてマーク h--s 2015年3月31日 8:19
    2015年3月31日 7:06
    モデレータ
  • 書き込んだ後で、trapemiyaさんがイベントについて言及されておられたので、私も一言。
    Livet の ViewModel には、弱参照のイベントリスナを一括管理できるプロパティが用意されてるので、私の場合 ViewModel のイベントはそれを使って管理しています。かなり便利です。

    ぜひ 「フォーラムでご質問頂くにあたっての注意点」 もご覧ください https://social.msdn.microsoft.com/Forums/ja-JP/ca9ecfb7-4407-4fcb-b8bd-207d68257e68?forum=announceja

    2015年3月31日 7:15
    モデレータ