none
MVVMモデルのWPFのコーディングの方法についてご質問 RRS feed

  • 質問

  • 現在、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 Get

            Set(ByVal value As HeaderInfo)
                If Not IsNothing(_HeaderInfo) AndAlso (_Result.Equals(value)) Then
                    Return
                End If
                _HeaderInfo = value
                'Detail情報の取得処理
                dim Detail =  GetDetail(_HeaderInfo)
       DetailRecord =  Detail          

            End Set
        End Property
    ---------------------------------------------

    このような書き方のような気がしますが、書いていて物凄く違和感を感じます。

    BのViewModelを作成時に、AのViewModelで取得するのものなのでしょうか

    皆さんはどのように方法で実装されているのでしょうか?
    お手数をおかけしますが、ご教示をお願い致します。

    2012年6月18日 11:23

回答

  • はじめまして、Posauneと申します。

    さて、ご質問いただいたのですが、もう少しコンテキストを明らかにしてもらわないと答えにくいところがいくつかあるかな、と思います。

    >> このような書き方のような気がしますが、書いていて物凄く違和感を感じます。

    まず、感じられている「違和感」とはどういったものなのでしょうか?個人的にはDetail情報をそのクラス自身が取りに行くのも考え方の一つとしては有りだと思うのですが。。。ViewModelの責務を超えている、というように感じているなら、それはViewModelAとViewModelB、という関係ではなく、省略されているModelもあわせて考えないといけない問題だと思います。

    その場合、開く画面がモーダルなのか・モードレスなのか?、Viewerだけなのか・データ永続化有りの編集ウィンドウなのか?などでその辺りの設計は色々と変わってくるかな、と思います。

    文章書いてばっかりもアレなので、僕ならこうするかな?という例をコミュニケーション図で上げておきます。モーダルで出るんだろうな、という想定です。データの永続化ができるかどうかはModelの実装次第になりそう。(ViewModelBが作ってもありなんじゃない?といっておきながら個人の好みではAに作らせたいですね。)

    ともかく、もう少しやりたいことと違和感の正体を明確にしていただければと思います。

    • 回答としてマーク VbBeginer001 2012年6月20日 13:39
    2012年6月18日 15:36
  • すいません、いろいろと返信を考えたのですが、本件は前提として確認したい項目がありすぎて非常に難しかったので、資料のご案内となります。

    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
    2012年6月19日 16:06

すべての返信

  • はじめまして、Posauneと申します。

    さて、ご質問いただいたのですが、もう少しコンテキストを明らかにしてもらわないと答えにくいところがいくつかあるかな、と思います。

    >> このような書き方のような気がしますが、書いていて物凄く違和感を感じます。

    まず、感じられている「違和感」とはどういったものなのでしょうか?個人的にはDetail情報をそのクラス自身が取りに行くのも考え方の一つとしては有りだと思うのですが。。。ViewModelの責務を超えている、というように感じているなら、それはViewModelAとViewModelB、という関係ではなく、省略されているModelもあわせて考えないといけない問題だと思います。

    その場合、開く画面がモーダルなのか・モードレスなのか?、Viewerだけなのか・データ永続化有りの編集ウィンドウなのか?などでその辺りの設計は色々と変わってくるかな、と思います。

    文章書いてばっかりもアレなので、僕ならこうするかな?という例をコミュニケーション図で上げておきます。モーダルで出るんだろうな、という想定です。データの永続化ができるかどうかはModelの実装次第になりそう。(ViewModelBが作ってもありなんじゃない?といっておきながら個人の好みではAに作らせたいですね。)

    ともかく、もう少しやりたいことと違和感の正体を明確にしていただければと思います。

    • 回答としてマーク VbBeginer001 2012年6月20日 13:39
    2012年6月18日 15:36

  • 返信ありがとうございます。

    ご質問頂きました、違和感の件ですが

    Headerというプロパティに値をセットするだけで
    勝手にDetailを取りにいくという点がなんとなく納得いきません。

    タイミング的には確かにHeaderが変更されれば、必ずDetailが変更されるので
    プロパティ変更時に書いておけば楽な気はするのですが、
    もし、Headerセット時にDetailが無かった場合はどうなるのかといった疑問もあります。

    ViewModelBはHeaderとDetailというプロパティを持つ事になるのですが
    一つのプロパティにセットすると、もうひとつのプロパティは勝手に取るというのが
    外側から、見た時に不自然な気がするのです

    二つプロパティがあるなら、別々にセットする。もしくは一つセットした後取りに行ってもらう
    というの方が分かりやすい気がするのですが、整理された書き方が思いつかなかったのでご質問
    させていただきました。

    開く画面(ViewModelB)はモーダルで変更・削除も可能な画面を想定していました。

    後、申し訳ありませんPosauneさんのコミュニケーション図を見させて頂いてご質問なのですが
    Modelでクエリ等を発行し、生成するというのはMVVMでは割とある手法なのでしょうか?

    サイトなのでよく見かけるMVVMのサンプルでは
    ViewModelがModelを作成、Modelは何もしないというパターンが多かった為
    (まぁサンプルなので簡易的な作りといのもあるかもしれませんが)
    MODELはあまり色々しないのかなと勝手に思ってました

    何か根本的に考え方が違ってる気がして、不安になってご質問させて頂きました。
    勉強不足で申し訳ありません

     

    2012年6月19日 0:35
  • 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/

    2012年6月19日 7:56
    モデレータ
  • trapemiyaさん、ご回答ありがとうございます。

    1つのプロパティの変更で、他のプロパティが変更されるという事はおかしな事ではないんですね

    あまり、そのようなパターンが無かったので、馴染めなかったです。コンストラクタで渡すと なんとなくイメージに近い気がします。

    頂いたご意見から考えると、ViewModelより、Modelの方が色々と処理をするのでしょうか

    ViewModelはModelを作って、LoadやGet等指示を出したら 。 Model側がクエリ等を発行してDB等からデータを取得するようなイメージなのでしょうか

    C#ですと、色々サンプルやフレームワークがあるのですがVB.NETで学習をしていると中々なくて、進まないですが

    ご意見参考になります。ありがとうございます。

    2012年6月19日 12:30
  • 今回のそのものズバリというのは無いでしょうが、VBでWPF系の情報だとこちらのBlogがあるかなと思います。

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


    かずき Blog:http://d.hatena.ne.jp/okazuki/

    2012年6月19日 14:40
  • すいません、いろいろと返信を考えたのですが、本件は前提として確認したい項目がありすぎて非常に難しかったので、資料のご案内となります。

    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
    2012年6月19日 16:06
  • 今回のそのものズバリというのは無いでしょうが、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/

    2012年6月20日 1:50
    モデレータ
  • かずきさん、ありがとうございます。

    ご紹介頂いたBlogも参考にさせて頂きます。

    2012年6月20日 10:34
  • ありがとうございます。

    分からない時に色々調べると結構良くたどりつくサイトで利用させていただきます。

    いつもピンポイントでしか見てないのですが、今度じっくりと見てみます!

    2012年6月20日 12:03
  • ありがとうございます。

    資料の方拝見いたしました。

    どうやら私はMODELをいわゆるMVCのモデルのイメージで作成していたみたいです。

    MODELはほぼフィールドのみでVIEWMODELが色々と値を取得して設定していました。

    もう一度拝見した資料を参考に考えてみたいと思います。

    (資料を見た後に、Posaueさんに頂いた解答を見ると、より分かりやすかったです。)

    MVVMにつまづいて、XAMLにつまづいてとわからないことばかりなので、また参考にさせて頂きます。

    ありがとうございます

    2012年6月20日 12:09
  • ひらぽんさん、ご回答ありがとうございます。

    いつも参考にさせていただいております。

    私はVB.NETで勉強中なのですが、VB.NETのソースサンプルがが少なく困る事が多いので、

    いつも参考に(たまにまるまるコピー等)させていただいています。

    LIVETもインストールはしたのですが、自分でもうすこし勉強してわかるようになってから使ったほうがいいのかと

    まだ、使用していませんが、是非使ってみたいと思います。

    MVVMは従来とは考え方をがらっと変えたほうがいいのでしょうか。

    サンプルのソースがとてもありがたいです。(また)参考にさせていただきます

    2012年6月20日 12:19
  • 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はデータアクセスなども含みます。

    2012年6月20日 12:33
  • 遅くなりました。すみません。

    頂いたご意見から考えると、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/

    2012年6月21日 2:35
    モデレータ