質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • WPF

    826questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • MVVM

    106questions

    MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

MVVMでViewModel同士の連携させるための一般的な方法が知りたい

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 7,149

mikupedia

score 127

WPF + Prism + ReactiveProperty(Rx)を使ったアプリケーションを作成しています。
MVVMパターンでViewModelの連携を取る(連携させて良いかも含めて)一般的な方法が知りたいです。

例えばAViewModelのプロパティの値が変更されたときに、
BViewModel、CViewModelのプロパティも変更するといったことを
みなさんがどのように実現させているか教えてください。

ViewModelは全て1つのプロジェクトで管理されていて、いずれもシングルトンです。
AViewModelのプロパティの値はViewの表示状態を管理するためだけに使用します。

私が思いつく方法を書いてみましたが、別の方法などあれば参考にさせてください。

方法①

EventAggrigatorを利用してイベントを発行/購読する。
EventAggrigatorは本来モジュール同士連携させるためのもの。
このようなViewModel同士の連携での使用には違和感がある。

方法②

DIコンテナを利用してViewModelを注入する(BViewModel、CViewModel→AViewModel)
AViewModelにBViewModelとCViewModelのインスタンスを注入。
AViewModelのプロパティ変更されたタイミングでBViewModelとCViewModelのプロパティを変更。

方法③

DIコンテナを使用してViewModel注入する(AViewModel→BViewModel、CViewModel)
BViewModelとCViewModelにAViewModelのインスタンスを注入。
AViewModelのプロパティの変更監視してBViewModelとCViewModelのプロパティを変更。

ViewModel同士を互いに操作させてはダメ?

MVVMのModelにまつわる誤解
このサイトではViewModel同士にお互いを操作することは好ましくない旨が書かれています。
今回のようなViewModel同士を連携させることに若干違和感を覚え、なんとなくもやもやしています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+4

私もMVVMパターンで設計する時、毎回悩みます。
ViewModelは特に。
そんなに経験は多くないですが、私の見解をまとめます。

一般的にMVVMパターンにおいてViewModel同士を互いに操作することは、少なくとも私の知る限りありません。

例えばAViewModelのプロパティの値が変更されたときに、
BViewModel、CViewModelのプロパティも変更するといったことを
みなさんがどのように実現させているか教えてください。

この内容を私が実現するのであれば、それぞれのViewModelの変更対象プロパティを"Value"とし、"Value"プロパティを実装した"XModel"を作成します。
XModelのValueプロパティの変更通知イベントをそれぞれのViewModelで購読し、そのイベントの着火後にViewModelのValueプロパティを変更する
と言った流れにすると思います。

方法①

はViewModel同士の連携に使うべきではないでしょう。
使うならViewModelとModelの連携です。

方法②, ③

ViewModelをDIするとインスタンスの生成順序がどちらかに依存してしまうので良くないと思います。
ViewModelがViewModelに依存するというのも違いますし。

それぞれのレイヤーをより疎結合にすることで、ユニットテストが容易に実装・修正できるため、できるだけ結合度は下げるほうが望ましいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/08 10:00 編集

    IYEMON018 様

    ご回答ありがとうございます。
    ViewModel同士を互いに操作させず、連携させたいのであればModel側で行うほうが良いということですね。

    少々気になったのですが、
    今回のようにViewの表示状態を管理するようなプロパティ、
    言い方を変えるとプレゼンテーション側のステートとなりますが
    Model側で持っても構わないのでしょうか?

    記載したサイトではViewModelはModelの影(1対1)となっていたので、
    今回のような場合ではAViewModelはAModel、BViewModelはBModel、CViewModelはCModelを持ち、
    それぞれのModelにシングルトンのXModelインスタンスを注入してValueプロパティの操作および
    変更通知イベントの購読を行う感じでしょうか。

    Model-ModelまたはModel-ViewModelであればEventAggrigatorによる祖結合なイベントのやり取りを行ってもよさそうなので場合によって使い分けてもよいかもしれませんね。

    Prism for Windows RuntimeのEventAggregator
    https://code.msdn.microsoft.com/windowsapps/Prism-for-Windows-17212e0d

    キャンセル

  • 2017/08/08 10:25

    記載したサイトのコメントに以下のようなコメントがあるのを見落としていました。ViewModelとModelは1対1とは限りませんね。
    >Modelの一つのプロパティに対して、二つのVew-ViewModelの対が紐づくことがあるでしょうし、その複数の値が同時に見かけ上変化するのはModelの変更を二つのViewModelが監視しているおかげですね。

    キャンセル

0

今回のようにViewの表示状態を管理するようなプロパティ、
言い方を変えるとプレゼンテーション側のステートとなりますが
Model側で持っても構わないのでしょうか?

ViewのステートはViewModelに持たせるべきだと思います。
Modelがそのステートを持ってしまうとViewに依存せざるを得なくなりますから。

記載したサイトではViewModelはModelの影(1対1)となっていたので、
今回のような場合ではAViewModelはAModel、BViewModelはBModel、CViewModelはCModelを持ち、
それぞれのModelにシングルトンのXModelインスタンスを注入してValueプロパティの操作および
変更通知イベントの購読を行う感じでしょうか。

その認識で合っています。
AModel, BModel, CModelは同一Modelでもいいと思います。
あるいは、XModelやYModelを持つデータストアのようなModelにするという選択肢もあります。
このあたりは実際のプロジェクトごとに最適な方法を選択してください。

記載したサイトのコメントに以下のようなコメントがあるのを見落としていました。ViewModelとModelは1対1とは限りませんね。
>Modelの一つのプロパティに対して、二つのVew-ViewModelの対が紐づくことがあるでしょうし、その複数の値が同時に見かけ上変化するのはModelの変更を二つのViewModelが監視しているおかげですね。

私の経験では、むしろViewModelとModelは多対1となることがほとんどです。
1つのViewで扱うデータが1つ以上あることはよくありますし、それならViewModelが複数のModelを監視しているべきですから。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/11 00:24

    IYEMON018 様
    私自身ViewModelとModelの境界線が少しわからなくなっていましたが、
    なんとなく雰囲気的なものはつかめた気がします。
    ただやっぱりもやもやしているところもあるのでこればっかりはリファクタリングしていく過程でコツをつかむしかなさそうですね・・・

    キャンセル

0

私の場合は、複数のView/ViewModelで共有する情報になった時点てModelで管理するようにしています。

例えば、ListBoxの選択項目の場合を考えてみます。
ViewAではListBoxと決定ボタンを実装し、ユーザーは決定した項目をModelに伝えます。ここまでは問題ないと思います。
次に、まだ決定してないがViewAで選択されている項目の内容を別のViewBに表示したくなったとします。
そのまま考えると、ViewAのListBox.SelectedItem を ViewBでも参照したくなりますが、ここで考えを変えます。

  • ViewB はModelの変数Aを表示する
  • ViewA はModelの変数Aを変化させる

このように考えるとこの情報はViewのステートでなくModelの情報と捉えることができます。

このサイトではViewModel同士にお互いを操作することは好ましくない旨が書かれています。

私も同じように考えます。極端な例ですと、ViewAとViewBは別環境でネットで接続されているということもありえます。ViewModel間の連携にネットまで考えたくありませんしね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/11 00:53

    neelabo 様
    SelectedItemがViewの表示形式とModelの形式が異なっていた場合、
    AViewのSelectedItemは表示用にXModelから受け取ったデータをAViewModel内でItemViewModel型に加工します。
    Listが選択されたら今度はその逆でVViewModelでItemViewModel型をSelectedItemに加工して元の形式にしてModelに戻します。
    BViewでもAViewとSelectedItemが同様の形式の場合、BViewModelでXModelのSelectedItemの変更通知を監視して、今度はBViewModelで同様に加工します。
    こんな感じでしょうか。
    この工程が若干回りくどく感じましたがAViewとBViewで表示形式が異なる場合には効果を発揮しますね。
    かつAViewとBViewで同じ元データが参照されることになるので実質同じ選択項目が表示(選択)できるようになりますね。

    キャンセル

同じタグがついた質問を見る

  • WPF

    826questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • MVVM

    106questions

    MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。