MVVMでVMからViewを操作する考察
えムナウさんのViewのコードビハインドにコマンドを用意する方法が以下に公開されています。通常はVMにコマンドを実装するので、この逆転の発想は私にはなく、感激いたしました。
MVVM パターンで VM から VIEW を操作したい
http://blogs.wankuma.com/mnow/archive/2010/09/20/193090.aspx
さて、上の記事を受けてかずきさんが以下の記事を書かれています。
MVVMパターンでVMからVに通知する方法
http://d.hatena.ne.jp/okazuki/20100920/1284991744
この記事を読んだ時に気が付いたのですが、要はVMはViewのコマンドを知れば良いので、何もバインドで渡す必要はないのではないかと思いました。
検証しようと思いつつ時間が経ち(^^; griefworkerさんがえムナウさんの発想そのままの例をコード化されていました。
MVVM パターンで ViewModel から Viewを操作する方法
http://d.hatena.ne.jp/griefworker/20100922
さらに時間は経ち(^^; かずきさんの以下の記事。コマンドじゃなくてデリゲートを渡しているわけですが、これが私の検証しようと思っていた発想の根底でした。つまりは、VMはViewのコマンドを知ることが目的であり、必ずしもバインドでコマンドを渡す必要はないのだと。
MVVMパターンでVMからVを操作する方法 再考
http://d.hatena.ne.jp/okazuki/20100925/1285426626
ここでかずきさんが書かれているようなデリゲートで渡すのとは別に、コマンドで渡すという方法もありえます。
#かずきさんはデリゲートを渡すならイベントと大差ないんじゃないかと書かれていますが、イベントもデリゲートの一種なのでここではとりあえずデリゲートのみで考えます。
では、デリゲートで渡すのとコマンドで渡すのとどちらがいいのでしょうか? 結論から言えばデリゲートで十分目的が達成できてしまいます。もはや一般的に知られているRelayCommandやDelegateCommandなどはデリゲートへの中継を行っていることになり、その中継に意味がないのであればコマンドを使う必要が無いからです。
そもそもコマンドはXAMLでイベントハンドラと結びつけることを避けるために考えられたのではないかと思っています。それが正しければXAML以外の場所でコマンドを使う必要はあまりないということになります。
MVVMではViewとVMの関係に注視しがちですが、現実のコーディングとしては、View(XAML)、View(コードビハインド)、VMの3つがあることになります。ViewはVMのインスタンスを知っています。つまり、View(XAML)もView(コードビハインド)もVMのインスタンスを知っていることになります。View(コードビハインド)に何もコードを書かないのが良いと言われることもありますが、そんなことはないと思います。私はMVVMとして守らないといけないことは以下のことだと現段階で結論付けていますので、それを守ればView(コードビハインド)にコードを書くことはOKです。
1.ViewはVMを知っている。つまり、View(XAML)、およびView(コードビハインド)もVMを知っている。
2.VMはViewを知らない。知らないがViewが存在しており、かつ自分を利用してくれていることを知っているので、Viewに対して操作を行う。操作は疎結合を保ったまま行う必要があるので、イベント、デリゲート、コマンドなどで行う。
3.View(XAML)とView(コードビハインド)は疎結合が望ましい。疎結合であればUIの変更が行いやすい。疎結合であるとは、例えばView(コードビハインド)にView(XAML)のコントロールのイベントハンドラなどを書かない。
View側 VM側 View(XAML)---------------->ViewはVMを知っている。VMはView(XAML)を知らない。 | | 疎結合が望ましい。 | | View(コードビハインド)-------->ViewはVMを知っている。VMはView(コードビハインド)を知らない。
VMはViewの存在を知りませんが、Viewが自分を利用していることは知っています。ですから、OnPropertyChangedを発するなどしてViewに知らせています。これはバインドの仕組みを使ってViewに伝達されていますが、かずきさんがデリゲートを実行してViewを操作したのと根本的には同じ概念です。
結論として、VMはXAMLでない以上、View(コードビハインド)のコマンドをVMにバインドするのはあまり意味がなく、View(コードビハインド)からVMにコマンドを渡されてそれを実行するならデリゲートを渡してしまえば良いというは話もあり・・・
つまり(ホントに結論)、View(コードビハインド)でコマンドを公開しても、そのコマンドをどのXAMLでも利用しないであろうから、あんまり意味がないのかなぁという結論です。コマンドを使っちゃダメということじゃないですけども。みなさんどう思われます? この辺りは悩むんですよね・・・悶々と悶々と。