2011年10月31日月曜日

MVVMでApplicationCommandsのコマンドを使うには?

WPFの定義済みコマンドを使用する方法

WPFには、一般的に使えそうなコマンドを定義したApplicationCommandsクラスがあります。ここにCopyPasteOpenみたいなコマンドが揃っています(同じようなクラスにMediaCommands、NavigationCommands、ComponentCommands、EditingCommandsってのがあります。詳しくは[MSDN]コマンド実行の概要参照)。

ここに定義されているのはRoutedCommandなので、コマンドを実行するコントロール(CommandSource)と処理するコントロール(CommandTarget)を別にすることができるみたい。具体的には、処理するコントロールにCommandBindingを設定すればいいみたい。以下はApplicationCommands.OpenButtonで実行してWindowで処理するイメージとXAML例。

 
<Window>
  (中略)
  <Window.CommandBinding>
    <CommandBinding Command="Open" Executed="DoOpen" />
  </Window.CommandBinding>
  <Grid>
    <Border>
      <Button Command="Open" Content="Open" />
    </Border>
  </Grid>
</Window>
(検証してないので動くかどうかは不明・・・)

DoOpenはViewModel出定義したコマンドのExecutedイベントハンドラ。つまりViewModelが処理用のメソッドを公開すれば、ViewModelでコマンドの処理を実装できるってこと。実際にコマンドが実行されると↓みたいな流れでDoOpenが呼ばれる(多分)。

 

これでApplicationCommandsの定義済みコマンドを使うことが出来ました。

MVVMにおけるCommandBindingの問題点

でもこれMVVMでやっちゃダメだよね。

なんでって、CommandBindingExecutedイベントのイベントハンドラ(ExecutedRoutedEventHandler)の定義って↓でしょ。

public delegate void ExecutedRoutedEventHandler (
 Object sender,
 ExecutedRoutedEventArgs e
)

これのsenderって、コマンドを実行したコントロール(CommandSource)が入るんですよね。そんなものViewModelに渡しちゃダメですよね? ViewModelがコントロールなんて受け取った日には、ViewとViewModel分けた意味がなくなってしまうので。

そこで問題だ。CommandBindingを使わずにどうやってApplicationCommandsのコマンドを使うか?

3択―ひとつだけ選びなさい

  • 答え①ハンサムな私は突如CommandBindingを使わないアイデアをひらめく
  • 答え②Microsoftが新しいクラスを提供してくれる
  • 答え③使えない。現実は非情である。

答え②に○を付けたいが、MicrosoftはMVVM関連ではBehaviorが最近入ったばかり、新たに追加クラスを提供してくれることは期待できない。

やはり答えは……………①しかねえようだ!

全部独自コマンドにすれば問題ないけど、やっぱりOpenとかNewとかは標準で定義されているコマンドを使いたいよね。Trigger&ActionBehavior使って、パラメータ渡さないメソッドにバインディングするような仕組みを作るか。あ、でもドラッグアンドドロップの時どうしよう。。。Object型のパラメータは有りにするか。でもそもそもViewModelが公開していいのはプロパティとコマンドだけだよね。。。メソッドを公開するという仕組み自体がダメか。。。イベントハンドラ付きのプロパティ定義する?でもそれって独自コマンド定義するのとあんまり変わらないような。。。。。。。。。。。

「答え-③ 答え③ 答え③」

どうしたもんかなー

参考

Posted by Picasa

0 件のコメント: