トップ回答者
MVVMモデルのWPFのコーディングの方法についてご質問

質問
-
現在、WPFを勉強を兼ねて色々触っているところです。
だいぶ遅まきながら、
MVVMモデルに沿ったWPFアプリケーションを作成しようとしており、
いろいろなサイトを見ながら試しているのですが、分からない事が多く
質問させていただきます。Header情報の一覧がある画面Aから、データを選択すると、そのDetailの情報を表示する画面B
を開くという簡単なアプリを作成しています。この場合、下記のような構成を検討しています。(Modelは割愛しております)
・AのView
・AのViewModel
・BのView
・BのViewModel処理の流れとしては、
①画面Aでデータを選択した際に、AのViewModelが、BのViewModelを作成し、Headerの情報をBのプロパティとしてセットする
②BのViewModelはHeader情報を元にDetailの情報を取得する。
③AのViewModelがViewBを作成し、BのViewModelをバインドする。と、上記のような流れになると思うのですが、この場合に②のDetail情報の取得は
どのようにコーディングすべきなのでしょうか?単純に考えれば
---------------------------------------------'BのViewModel(一部)
'BのHeader情報のプロパティ
Public Property HeaderRecord() As HeaderInfo
Get
Return _HeaderInfo
End GetSet(ByVal value As HeaderInfo)
If Not IsNothing(_HeaderInfo) AndAlso (_Result.Equals(value)) Then
Return
End If
_HeaderInfo = value
'Detail情報の取得処理
dim Detail = GetDetail(_HeaderInfo)
DetailRecord = DetailEnd Set
End Property
---------------------------------------------このような書き方のような気がしますが、書いていて物凄く違和感を感じます。
BのViewModelを作成時に、AのViewModelで取得するのものなのでしょうか
皆さんはどのように方法で実装されているのでしょうか?
お手数をおかけしますが、ご教示をお願い致します。
回答
-
はじめまして、Posauneと申します。
さて、ご質問いただいたのですが、もう少しコンテキストを明らかにしてもらわないと答えにくいところがいくつかあるかな、と思います。
>> このような書き方のような気がしますが、書いていて物凄く違和感を感じます。
まず、感じられている「違和感」とはどういったものなのでしょうか?個人的にはDetail情報をそのクラス自身が取りに行くのも考え方の一つとしては有りだと思うのですが。。。ViewModelの責務を超えている、というように感じているなら、それはViewModelAとViewModelB、という関係ではなく、省略されているModelもあわせて考えないといけない問題だと思います。
その場合、開く画面がモーダルなのか・モードレスなのか?、Viewerだけなのか・データ永続化有りの編集ウィンドウなのか?などでその辺りの設計は色々と変わってくるかな、と思います。
文章書いてばっかりもアレなので、僕ならこうするかな?という例をコミュニケーション図で上げておきます。モーダルで出るんだろうな、という想定です。データの永続化ができるかどうかはModelの実装次第になりそう。(ViewModelBが作ってもありなんじゃない?といっておきながら個人の好みではAに作らせたいですね。)
ともかく、もう少しやりたいことと違和感の正体を明確にしていただければと思います。
- 回答としてマーク VbBeginer001 2012年6月20日 13:39
-
すいません、いろいろと返信を考えたのですが、本件は前提として確認したい項目がありすぎて非常に難しかったので、資料のご案内となります。
Model周りなど誤解っぽいものが見えますので、試しに一度こちらを読んでいただけないでしょうか?
http://ugaya40.net/mvvm/mvvm_document.html
VB/C#関係なくコードは出てきません。読んでいただいた上でもう一度考えていただけると今のコードの形も疑問点も大分変わってくる可能性もあるかと思っております。
書いたコードに違和感がある場合、コードではなくMVVMそのものの概念に立ち返ってみるのは大事なことです。MVVMを考慮することで自分が書くコードに何をもたらせたいのかを見つめるためには、MVVMの概念をしっかりと理解していることが大切です。
サンプルコードからMVVMなどは学べません。
なお、疑問点・突っ込みなどいろいろと御用がある場合はぜひTwitterにいらして私 - @ugaya40に声をかけてみてください。@ITのMVVM記事やMVVM関連記事・各種MVVM関連セッションでの資料を大量に公開している者です。
Twitterは掲示板より多少のリアルタイム性がありますので、ここよりいろいろお答えしやすいと思います。
- 回答としてマーク VbBeginer001 2012年6月20日 13:40
すべての返信
-
はじめまして、Posauneと申します。
さて、ご質問いただいたのですが、もう少しコンテキストを明らかにしてもらわないと答えにくいところがいくつかあるかな、と思います。
>> このような書き方のような気がしますが、書いていて物凄く違和感を感じます。
まず、感じられている「違和感」とはどういったものなのでしょうか?個人的にはDetail情報をそのクラス自身が取りに行くのも考え方の一つとしては有りだと思うのですが。。。ViewModelの責務を超えている、というように感じているなら、それはViewModelAとViewModelB、という関係ではなく、省略されているModelもあわせて考えないといけない問題だと思います。
その場合、開く画面がモーダルなのか・モードレスなのか?、Viewerだけなのか・データ永続化有りの編集ウィンドウなのか?などでその辺りの設計は色々と変わってくるかな、と思います。
文章書いてばっかりもアレなので、僕ならこうするかな?という例をコミュニケーション図で上げておきます。モーダルで出るんだろうな、という想定です。データの永続化ができるかどうかはModelの実装次第になりそう。(ViewModelBが作ってもありなんじゃない?といっておきながら個人の好みではAに作らせたいですね。)
ともかく、もう少しやりたいことと違和感の正体を明確にしていただければと思います。
- 回答としてマーク VbBeginer001 2012年6月20日 13:39
-
返信ありがとうございます。ご質問頂きました、違和感の件ですが
Headerというプロパティに値をセットするだけで
勝手にDetailを取りにいくという点がなんとなく納得いきません。タイミング的には確かにHeaderが変更されれば、必ずDetailが変更されるので
プロパティ変更時に書いておけば楽な気はするのですが、
もし、Headerセット時にDetailが無かった場合はどうなるのかといった疑問もあります。ViewModelBはHeaderとDetailというプロパティを持つ事になるのですが
一つのプロパティにセットすると、もうひとつのプロパティは勝手に取るというのが
外側から、見た時に不自然な気がするのです二つプロパティがあるなら、別々にセットする。もしくは一つセットした後取りに行ってもらう
というの方が分かりやすい気がするのですが、整理された書き方が思いつかなかったのでご質問
させていただきました。開く画面(ViewModelB)はモーダルで変更・削除も可能な画面を想定していました。
後、申し訳ありませんPosauneさんのコミュニケーション図を見させて頂いてご質問なのですが
Modelでクエリ等を発行し、生成するというのはMVVMでは割とある手法なのでしょうか?サイトなのでよく見かけるMVVMのサンプルでは
ViewModelがModelを作成、Modelは何もしないというパターンが多かった為
(まぁサンプルなので簡易的な作りといのもあるかもしれませんが)
MODELはあまり色々しないのかなと勝手に思ってました何か根本的に考え方が違ってる気がして、不安になってご質問させて頂きました。
勉強不足で申し訳ありません -
ViewModelBはHeaderとDetailというプロパティを持つ事になるのですが 一つのプロパティにセットすると、もうひとつのプロパティは勝手に取るというのが 外側から、見た時に不自然な気がするのです。
「もうひとつのプロパティは勝手に取る」という表現がよくわからなかったのですが、1つのプロパティを変更することによって、もう一つのプロパティが変化するということでしょうか?であれば、これ自体は特におかしなことではありません。例えば、IDataErrorInfoを実装している場合、そのクラスのあるプロパティが変化したタイミングで、IDataErrorInfoのErrorプロパティなどが変化します。
悩まれているところが今一つわからないのですが、HeaderからDetailを開くときに、コンストラクタでHeader情報を渡してしまうのもありではないかと思います。Detail画面を複数同時に開く場合、それぞれにViewModelが必要ですし、そのViewModelはそのHeader専用になりますから、最初に一度渡してしまえば、後からそれが変わることはないはずです。
MODELはあまり色々しないのかなと勝手に思ってました
Modelは特定の一つのクラスではなく、概念だと思った方が良いかもしれません。例えば、Modelが複数のクラスから構成されることは多々あるでしょう。複数のクラスとは、実際にViewにバインドするクラス(仮にUIオブジェクトと呼ぶことにします)、UIオブジェクトをコレクションとして提供するクラス、データベースなどからUIオブジェクトを作成するクラスなどです。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
-
trapemiyaさん、ご回答ありがとうございます。
1つのプロパティの変更で、他のプロパティが変更されるという事はおかしな事ではないんですね
あまり、そのようなパターンが無かったので、馴染めなかったです。コンストラクタで渡すと なんとなくイメージに近い気がします。
頂いたご意見から考えると、ViewModelより、Modelの方が色々と処理をするのでしょうか
ViewModelはModelを作って、LoadやGet等指示を出したら 。 Model側がクエリ等を発行してDB等からデータを取得するようなイメージなのでしょうか
C#ですと、色々サンプルやフレームワークがあるのですがVB.NETで学習をしていると中々なくて、進まないですが
ご意見参考になります。ありがとうございます。
-
今回のそのものズバリというのは無いでしょうが、VBでWPF系の情報だとこちらのBlogがあるかなと思います。
http://d.hatena.ne.jp/hilapon/
かずき Blog:http://d.hatena.ne.jp/okazuki/
-
すいません、いろいろと返信を考えたのですが、本件は前提として確認したい項目がありすぎて非常に難しかったので、資料のご案内となります。
Model周りなど誤解っぽいものが見えますので、試しに一度こちらを読んでいただけないでしょうか?
http://ugaya40.net/mvvm/mvvm_document.html
VB/C#関係なくコードは出てきません。読んでいただいた上でもう一度考えていただけると今のコードの形も疑問点も大分変わってくる可能性もあるかと思っております。
書いたコードに違和感がある場合、コードではなくMVVMそのものの概念に立ち返ってみるのは大事なことです。MVVMを考慮することで自分が書くコードに何をもたらせたいのかを見つめるためには、MVVMの概念をしっかりと理解していることが大切です。
サンプルコードからMVVMなどは学べません。
なお、疑問点・突っ込みなどいろいろと御用がある場合はぜひTwitterにいらして私 - @ugaya40に声をかけてみてください。@ITのMVVM記事やMVVM関連記事・各種MVVM関連セッションでの資料を大量に公開している者です。
Twitterは掲示板より多少のリアルタイム性がありますので、ここよりいろいろお答えしやすいと思います。
- 回答としてマーク VbBeginer001 2012年6月20日 13:40
-
今回のそのものズバリというのは無いでしょうが、VBでWPF系の情報だとこちらのBlogがあるかなと思います。
ご紹介ありがとうございます。状況が不明だったのでコメントを差し控えていたのですが、私のブログが紹介されたので出てきました。
ブログで公開してるコードは MVVM を学習中に書いてるものが多いため、最適解とは言えないコードも多く公開しています。また ugaya40さんが仰るとおり、コードだけで MVVM を習得することは難しいと思います。とはいえ VBによる MVVM 実装例や MVVMインフラである Livet の使用例として、少しはお役にたてるかも知れません。
1つのプロパティの変更で、他のプロパティが変更されるという事はおかしな事ではないんですね
もしかしたらプロパティ内に副作用的コードを実装することに対する違和感があるのでしょうか?確かにメソッド(およびプロパティ)に副作用が存在しない方が理想的ですが、ビューの問題を解決するために、あえて副作用的実装を設けるのも止むを得ない場合があると思います。私も ViewModel のプロパティ内で他のプロパティを設定したり、検証用コードを書いたり、メソッドを呼び出したりと頻繁に行っています。
''' <summary> ''' 業務開始時刻(分)を取得・設定します。 ''' </summary> Property StartMinute() As String <DebuggerNonUserCode()> Get Return _startMinute End Get Set(value As String) If (String.IsNullOrEmpty(value)) Then _errors("StartMinute") = "開始時刻(分)が設定されていません。" ElseIf (IsNumeric(value) = False) Then _errors("StartMinute") = "数値を入力してください。" ElseIf (CInt(value) >= 60) Then _errors("StartMinute") = "60 以上の値は設定できません。" Else _errors("StartMinute") = Nothing End If _startMinute = value Me.RaisePropertyChanged("StartMinute") ' 終了時刻の検証 Me.ValidateOpenTime() Me.UpdateCommand.RaiseCanExecuteChanged() End Set End Property
以上、あくまで雰囲気的なものだけ感じ取って頂ければ幸いです。
最後になりますが、MVVM はあくまでビューの問題を解決するためのパターンです。ビューの問題を解決するために、従来の定石的なものをあえて崩すケースがあるのも仕方ないのかなと感じてたりします。
ひらぽん http://d.hatena.ne.jp/hilapon/
-
-
MVCでもModelの考え方は実はそんなに変わりません。なぜならMVVMはMVC系の一つですし、どちらもその目的はPresentationDomainSeparationですから。
リッチクライアントとWebでModelのオブジェクトが自身の状態を管理する必要があるかどうかの違いでしかありません。
Webの場合は、作ったオブジェクトは表示用であり、それがメソッドを持っていて自身の状態を変化させるだとかそういった必要がないんですね。なにせ1リクエストごとに必要なオブジェクトを生成して破棄するのがWebですから。セッションやDBはシステムにとってはファイルへの保存と一緒で外部ストレージです(開発者にとって値のライフサイクルをオブジェクトとして管理の必要がない)。
リッチクライアントのMVC - 例えばAndroid。あるいはWindowsFormsでのMVC/MVP。MVVMもそうですが、これらのMVC系Modelはでは基本的にデータの入れ物だけになることがないのです。資料を見ていただいたらわかると思いますが、成り立ちから言っても、責務から言ってもその考え方ではメリットが生まれません。
WikipediaのMVC - http://ja.wikipedia.org/wiki/Model_View_Controller
などを見ていただいてもわかりますが、WebMVCでも、Modeはデータアクセスなども含みます。 -
遅くなりました。すみません。
頂いたご意見から考えると、ViewModelより、Modelの方が色々と処理をするのでしょうか
ViewModelはModelを作って、LoadやGet等指示を出したら 。 Model側がクエリ等を発行してDB等からデータを取得するようなイメージなのでしょうか
おおよそ、そのイメージでOKです。ViewModelがModelのインスタンスを作成し、ModelがViewにバインドするためのオブジェクト(ここではUIオブジェクトと呼ぶことにします)を返してくるというイメージです。ここでいうModelはデータプロバイダー的な役割になっています。(ですから私はこのクラスにModelという言葉を使って命名することはありません。データプロバイダーというような名前を付けた方がわかりやすいという理由からです。また、下で書きますが、Model = UIオブジェクトになるケースもあり、Modelという言葉があやふやだからです。そうやって名前を付けていきますので、Modelという言葉が付いたクラスは私の作成するプログラム中には存在しません。存在してはいけないという意味ではなく、私の場合に限って言えば、自然とそうなったというだけです。)
よくあるサンプルは簡単な例が多く、ViewModelがModelを作成していますが、この場合、Model = UIオブジェクトになっています。つまり、同じModelという言葉を使っても、役割が異なっていることがあるということに注意して、サンプルや資料を読まれると良いと思います。
以上のことは、私が先に書いた、Modelはあるクラスのことではなく、概念として捉えた方が良いのではないかということの理由でもあります。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/