前回説明したように、WPFにはデータ・バインディングという仕組みがあり、ビューの外部から表示したいデータを与えることができる(外部から与えるデータは、後述する「ビューモデル(ViewModel)」というものになる場合が多い)。2に示すように、表示したいデータだけでなく、コマンドを外部から与えることも可能である。することで、ビュー内にはデータも処理も書く必要がなくなり、一般にテストが難しくなりがちなビューを極力小さくすることができる。データ・バインディングでビューの外部からコマンドを与えるこの方法におけるコマンドの利用手順は以下のようになる。1のような書き方をする。parameter){MessageBox.Show("コマンドが実行されました。ICommand.ExecuteMessageBox.Show("コマンドが実行されました。データ・バインディングを使ったコマンド処理(上:XAML、中:C#、下:VB)この書き方が、後述するMVVMパターンでのコマンド処理の基本となる。ICommandインターフェイスの実装については、本稿後半のMVVMパターンの項で再度説明を行う。command)を使う方法である。WPF標準で用意されたICommandインターフェイスの1実装として、RoutedCommandクラスというものがあり、このクラスを継承した派生クラスのオブジェクト(=これが、ルーティング・コマンドの実体)を用いる。ちなみに、WPFでは標準で、RoutedCommandクラスを継承したRoutedUICommandクラスが用意されている。3に示すように、RoutedCommandクラスでは、Executeメソッドが呼び出された際にExecutedなどのルーティング・イベントを発生させる。このルーティング・イベントをツリー構造の上位のUI要素で拾って処理することになる。ルーティング・コマンドRoutedCommandクラスは、以下のようなルーティング・イベントを発生させる(※トンネル・イベントでは、要素ツリーのルートからイベント発生源となる要素に向かって、要素ツリーを掘り進むようにイベント・ハンドラが呼び出される。トンネル・イベントの名前には原則として「Preview」というプレフィックスが付く。バブル・イベントでは、イベント発生源となる要素からルートに向かって、要素ツリーをたどりながら、浮かび上がるようにイベント・ハンドラが呼び出される)。Excuteメソッドが呼ばれたときに発生するトンネル・イベント。Excuteメソッドが呼ばれたときに発生するバブル・イベント。CanExcuteメソッドが呼ばれたときに発生するトンネル・イベント。CanExcuteメソッドが呼ばれたときに発生するバブル・イベント。ルーティング・コマンドを使う方法でのコマンドの利用手順は以下のようになる。RoutedCommandクラスを継承してルーティング・コマンドを自作するか、あるいは、WPF標準で用意されたルーティング・コマンド(=RoutedUICommandクラス)をそのまま利用する自作したルーティング・コマンドは(任意のクラスで)静的プロパティなどで公開しておく、一方、WPF標準のルーティング・コマンドは何もしなくてもよい(詳しくは後述するが、ApplicationCommandsクラスなどで静的プロパティとして公開されているため)ルーティング・コマンドの実体(=公開済みの静的プロパティの値)を、<Button>要素や<MenuItem>要素などのCommandプロパティに与えるルーティング・コマンド自作した場合、x:Staticマークアップ拡張*1などを用いて値に与える(本稿ではこの手法は割愛)標準のルーティング・コマンドは、例えば「Command="ApplicationCommands.Copy"」*2などと書くだけで利用可能(詳細後述)コマンド処理を行う上位のUI要素でCommandBindingsプロパティを設定。.../>」のような記述により、何らかクラスの静的プロパティをXAMLコードで使用するためのもの。この例で指定しているApplicationCommands.Copy静的プロパティからはRoutedUICommandオブジェクトが得られる。WPF標準のルーティング・コマンド(=いずれもRoutedUICommandオブジェクト)は、利用目的別にいくつかのクラスにまとめられ(=コマンド・ライブラリ)、各クラスの静的プロパティとして公開されている。具体的には以下のようなクラスがある(EditingCommandsクラスのみ、System.Windows.Documents名前空間。それ以外はいずれもSystem.Windows.Input名前空間)。ファイルを開く、保存、ウィンドウを閉じるなど。ブラウザの戻る、ホームを開く、前項/次項を開くなど。リスト・アイテムやセルの移動、スクロール、フォーカスの移動など。テキスト編集用のコマンド。メディアの再生、停止、次のトラックへ移動など。2のような書き方をする。このコードでは、標準のルーティング・コマンドを利用している。e){MessageBox.Show("コマンドが実行されました。ExecutedRoutedEventArgs)MessageBox.Show("コマンドが実行されました。custom:RoutedCommandWindow.MyRoutedCmd}のように記述すればよい。この「cusutom」というXML名前空間に対応するxmlns:custom属性は、あらかじめXAMLコードのルートにある<Window>要素に追記しておく必要がある。下記のようなコードになる。xmlns:custom="clr-namespace:atmarkit06"Commandプロパティに設定しているPropertiesという値は、正確にはApplicationCommandsクラス(System.Windows.Input名前空間)のProperties静的プロパティを指す。ApplicationCommands.Properties}」と記述するべきだが、WPF標準のルーティング・コマンド群の場合、通常、Command属性への指定では「ApplicationCommands.」などを省略して「Command="Copy"」と簡潔に記述できる。このApplicationCommands.Properties静的プロパティより得られるルーティング・コマンドは、本来「プロパティ・ウィンドウを開く」という処理を表すものだが、説明の簡素化のために、ここではメッセージボックスの表示で代用している。ルーティング・コマンドは、ユーザー・コントロールを自作する場合や、コントロール・テンプレートを利用する場合などに特に有効である。連載第4回でスクロールバーへのコントロール・テンプレートの適用の例を挙げたが、テンプレート側でルーティング・コマンドを使ってExecutedなどのルーティング・イベントを発生させ、コントロール側の<CommandBindings>要素でそれを拾ってイベント(=コマンド)処理してもらうというような使い方が可能だ。●コマンド・ソースデータ・バインディングを使うにしろ、ルーティング・コマンドを使うにしろ、まずはコマンドの発生源(=コマンド・ソース)の設定が必要だ。WPFでは、コマンド・ソースを実装するためのICommandSourceインターフェイス(System.Windows.Input名前空間)があり、コマンド・ソースとなるUI要素を作る場合には、このインターフェイスを実装する。ICommandSourceインターフェイスは以下のようなメンバを持っている。発生させたいコマンドを設定する。ICommandインターフェイスのExecuteメソッドやCanExecuteメソッドの引数として渡されるパラメータを設定する。コマンドの実行対象を設定する。Pasteコマンドが実行される際に、どのUI要素に対して貼り付け処理を行うかなどを指定する。ルーティング・イベントでのみ利用可能。WPF標準で提供されているコマンド・ソースには、大きく分けてコントロールとインプット・バインディングの2種類ある。○コントロール<Button>要素や<MenuItem>要素など、一部のコントロールはICommandSourceインターフェイスを実装している。ルーティング・コマンドを用いたコマンド処理」で示した、<Button>要素のCommandプロパティを参照)。残念ながら、標準では左ボタンのクリック・イベントを拾ってコマンド実行する以外のことができない。SDKが必要になるなど、入門の範囲を超えてしまうため、本連載では割愛する)。○インプット・バインディングコントロールのような、目に見えるコマンド・ソース以外に、キーボード・ショートカットや特殊なマウス・ジェスチャーなどの入力系のイベントを拾ってコマンド実行するためのインプット・バインディングという仕組みがある。UIElementクラス(System.Windows名前空間)(=WPFのUI要素の共通基底クラス)にはInputBindingsというプロパティがあり、これに<KeyBinding>要素、もしくは、<MouseBinding>要素を与えることでインプット・バインディングを行う。3に示すようなXAMLコードを記述する。1と同様のビューモデルをデータ・バインディングすれば、「[Alt]+[Shift]+[X]キーを押す」「[Ctrl]キーを押しながらマウス・ホイールを回す」という操作を行った際にメッセージボックスが表示される。<KeyBinding>要素のGestureプロパティには、1つ以上の修飾キーと1つのキーを定義するKeyGestureクラス(System.Windows.Input名前空間)の値を単一の文字列で設定する。3に示す「Alt+Shift+X」などのような略記が可能になっている。3に示す「Ctrl+WheelClick」などのように略記で設定する。ちなみに、標準で用意されている(ApplicationCommandsクラスなどの静的プロパティとして公開されている)ルーティング・コマンドに対しては、最初からインプット・バインディングが設定されていて、何も記述しなくても、「Ctrl+S」でSaveコマンド、「Ctrl+C」でCopyコマンドなどというように、ルーティング・コマンドが実行される。前回と今回を通したここまでの説明を踏まえて、次のページではMVVMパターンについて解説する。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。