WPFの定義済みコマンドを使用する方法
WPFには、一般的に使えそうなコマンドを定義したApplicationCommands
クラスがあります。ここにCopy
、Paste
、Open
みたいなコマンドが揃っています(同じようなクラスにMediaCommands、NavigationCommands、ComponentCommands、EditingCommandsってのがあります。詳しくは[MSDN]コマンド実行の概要参照)。
ここに定義されているのはRoutedCommand
なので、コマンドを実行するコントロール(CommandSource)と処理するコントロール(CommandTarget)を別にすることができるみたい。具体的には、処理するコントロールにCommandBinding
を設定すればいいみたい。以下はApplicationCommands.Open
をButton
で実行して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でやっちゃダメだよね。
なんでって、CommandBinding
のExecuted
イベントのイベントハンドラ(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&Action
かBehavior
使って、パラメータ渡さないメソッドにバインディングするような仕組みを作るか。あ、でもドラッグアンドドロップの時どうしよう。。。Object
型のパラメータは有りにするか。でもそもそもViewModelが公開していいのはプロパティとコマンドだけだよね。。。メソッドを公開するという仕組み自体がダメか。。。イベントハンドラ付きのプロパティ定義する?でもそれって独自コマンド定義するのとあんまり変わらないような。。。。。。。。。。。
「答え-③ 答え③ 答え③」
どうしたもんかなー