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

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

新規登録して質問してみよう
ただいま回答率
85.48%
MVVM

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

WPF

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

Q&A

解決済

3回答

31442閲覧

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

mikupedia

総合スコア159

MVVM

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

WPF

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

1グッド

1クリップ

投稿2017/08/07 09:37

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同士を連携させることに若干違和感を覚え、なんとなくもやもやしています。

g_uo👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

私も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/07 12:32

IYEMON018

総合スコア202

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikupedia

2017/08/08 02:17 編集

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
mikupedia

2017/08/08 01:25

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

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/09 09:17

neelabo

総合スコア60

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikupedia

2017/08/10 15: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で同じ元データが参照されることになるので実質同じ選択項目が表示(選択)できるようになりますね。
guest

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/08 17:27

IYEMON018

総合スコア202

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mikupedia

2017/08/10 15:24

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問