8]コマンド・オブジェクトを作ってコントロールにバインドする方法と、コントロールの任意のイベントにコマンド・オブジェクトをバインドするヒントを説明する。Insider.NET連載目次このTIPSでは、データをUIのコントロールにバインドして表示する方法を紹介してきた。その主なメリットは、データ・バインディングによってUIとロジックを分離できることにある。分離したいことはほかにもある。コントロールのイベントとコードビハインドのイベント・ハンドラは密に結合しているが、分離できないだろうか?データ・バインディングのようにしてイベント・ハンドラを直接バインドできればよいのだが、残念ながらそれはできない。「コマンド・オブジェクト」をコントロールの「コマンド・プロパティ」にバインドすることで、ある程度は実現可能だ。本稿では、コマンド・オブジェクトを作ってコントロールにバインドする方法と、コントロールの任意のイベントにコマンド・オブジェクトをバインドするヒントを説明する。8版)」からダウンロードできる。2012)が必要である。これらを準備するには、第1回のTIPSを参考にしてほしい。ICommandインターフェイス「コマンド・オブジェクト」はSystem.Windows.Input名前空間のICommandインターフェイスを実装して作る。実装すべきメンバは次の3つである。メンバ説明CanExecuteメソッド現在、このコマンドが実行可能かどうかを返すExecuteメソッドコマンドの実行時に呼び出されるメソッドCanExecuteChangedイベントCanExecuteメソッドの返値が変わったときに、コマンド・オブジェクトから発生させるイベントICommandインターフェイスで実装すべきメンバコマンド・オブジェクトをバインドされたUIのコントロールは、CanExecuteメソッドを呼び出すことでコマンドを実行可能かどうか識別し、コントロールでイベントが発生したときにExecuteメソッドを呼び出す。コマンド・オブジェクトの内部で実行可能かどうかが変化するとCanExecuteChangedイベントが発生するので、コントロールはそれを受けてタイミングよくCanExecuteメソッドを呼び出すことで、コマンドの状態を確認できる。コントロールのコマンド・プロパティUIを構築するためのコントロールには、「コマンド・プロパティ」を持っているものがある。コマンド・プロパティの型はICommandインターフェイスであり、そこには前述のコマンド・オブジェクトをバインドできる。現在のところ、そのようなコントロールはまだ少ないのだが、例えばButtonコントロール(Windows.UI.Xaml.Controls名前空間)のCommandプロパティがある。これは、ボタンが押されたときにバインドされているコマンドが実行されるものだ。本稿では、これを使ってみよう。コマンド・オブジェクトを作るには?前述のICommandインターフェイスを実装したクラスを作成すればよい。Executeメソッドの処理内容は、直接記述してもよいし、汎用的に外部から与えてもよい。ここでは、オブジェクト生成時に外部から与えるようにしてみよう。CanExecuteメソッドは、本来はロジックがコマンドを受け付けられる状態にあるかどうかを返すのだが、ここではサンプルということで、コマンド・パラメータ(後述)だけを見て判定する。このサンプル・コードでは、CanExecuteメソッドの返値はコマンド・パラメータごとに常に同じ結果になるので、CanExecuteChangedイベントを発火させることはない。以上を実装すると、次のコードのようになる。ClassICommandインターフェイスを実装したクラス(上:C#、下:VB)このほかに、ファイルの先頭でSystem.Windows.Input名前空間をインポートする必要がある。サンプル画面コマンド・オブジェクトをバインドする画面を用意する。今回のサンプルはLayoutAwarePageクラスを継承したページにする必要がある*1。8]」の*5を参照してほしい。これは、後ほど、LayoutAwarePageクラスが提供するDefaultViewModelプロパティを利用するからだ。8]」をお読みいただきたい。LayoutAwarePageクラスを継承したページの用意ができたら、次のコードのように、Buttonコントロールを3つと、コマンドの処理結果を表示するためのTextBlockコントロール(Windows.UI.Xaml.Controls名前空間)を1つ配置する。/></StackPanel>......省略......画面にButtonコントロールを3つと、TextBlockコントロールを1つ配置した(XAML)コントロールのイベントにイベント・ハンドラを指定する場合とは異なり、イベントを処理するコードを全く記述していない状態でもビルドできる。ここで、3つのButtonコントロール全てにCommandParameter属性が定義してある。そこに指定した値がコマンド・パラメータとして、コマンド・オブジェクトのExecuteメソッドとCanExecuteメソッドに渡されるのだ。「button1」には、コードビハインドでコマンド・オブジェクトをバインドする(後述)。Command}」と指定することで、データ・コンテキスト中の「Command」という名前のコマンド・オブジェクトをバインドしている。コントロールのイベントにイベント・ハンドラを指定する方法では、コードビハインドでイベント・ハンドラが定義されていないとビルド・エラーになる。ところが、上のコードのようにコマンド・オブジェクトをバインドする方法では、指定したコマンド・オブジェクトが存在しなくても、ビルドして実行できる。画面のデザインとロジックの実装を分けて作業する場合、それはメリットになるだろう。コードからバインドするには?コマンド・オブジェクトを生成し、次いで、それをSourceプロパティに指定したBindingオブジェクトを生成する。コントロールのSetBindingメソッドを使って、そのBindingオブジェクトを結び付ければよい。今回のコマンド・オブジェクトは、インスタンス化するときにコマンドで実行する処理を与えるように作ってある。その処理は、コマンド・パラメータをそのままテキスト・ブロックに表示することにしよう(次のコード)。Subコマンドで実行する処理(上:C#、下:VB)このメソッドはコードビハインドに記述する。実際にバインドするコードは、次のようになる。コマンド・オブジェクトを生成する。実行されるコマンドはCommandActionメソッド。コマンド・オブジェクトを生成する。実行されるコマンドはCommandActionメソッド。cmd})コードからコマンド・オブジェクトをバインドする(上:C#、下:VB)このコードはLoadStateメソッドに記述する。これで実行してみよう。clicked」と表示されるはずだ。XAMLでバインドするには?まずXAMLコードで、コントロールのCommand属性にバインドを指定し、CommandParameter属性にコマンド・パラメータを指定する。コードビハインドでコントロールのデータ・コンテキストにコマンド・オブジェクトを設定する。XAMLコードの記述については、前述した「サンプル画面」の項で説明した。あとは、コードビハインドでデータ・コンテキストの「Command」という名前の場所にコマンド・オブジェクトを設定すればよい。先ほどの「コードからコマンド・オブジェクトをバインドする」コードに続けて、次のコードを記述する。cmdコマンド・オブジェクトをページのデータ・コンテキストに設定する(上:C#、下:VB)このコードを記述する場所は、LoadStateメソッドの末尾である。clicked」と表示されるはずだ。CanExecuteメソッドの効果さて、「コマンド・オブジェクトを作るには?」の項で作成したコマンド・オブジェクトのコードには、CanExecuteメソッドがあった。その中身は、コマンド・パラメータに「button3」という文字列が含まれていたらfalse/Falseを返すようになっている。これはどのような効果を発揮するのだろうか?実行時の画面は、次の画像のようになる。実行中の画面(部分)「button3」は、操作できない状態になっている。「button3」が操作できない状態であることが見て取れる。これがCanExecuteメソッドの効果だ。画面のロード時、コントロールはコマンド・オブジェクトのCanExecuteメソッドを呼び出す。CanExecuteメソッドがfalse/Falseを返した場合、コントロールはそのコマンドが利用できない状態であると認識する。そのときにコントロールの外観をどうするかの決まりはないが、Buttonコントロールではタップ/クリックできない状態を表す外観になるのだ。コマンド・オブジェクトの状態が変わったときに、コマンド・オブジェクトはCanExecuteChangedイベントを発火させる。バインドされているコントロールは、それを受けて再びCanExecuteメソッドを呼び出し、コントロールの状態を更新するのだ。以上でコマンド・オブジェクトを作って利用する方法の解説は終わった。Buttonコントロールのタップ/クリック・イベントだけがロジックと分離できても、そのほかさまざまなイベントが分離できないのでは、面倒なコマンド・オブジェクトを作成する意義は薄いのではないかと思われたかもしれない。さまざまなコントロールのイベントをロジックから分離するには、それらのイベントをそのコントロールの新しいコマンド・プロパティに変換するコードを追加すればよい。ユーザー・コントロールを作って、新しいコマンド・プロパティを実装するのだ。いっても、それも面倒な作業になる。そこで検討したいのが、MVVMフレームワークだ。Runtime」など、いくつかのフレームワークが公開されている。それらのフレームワークでは、V(ビュー)とVM(ビューモデル)を分離するための仕掛けの中に、イベントとイベント・ハンドラを分離する仕組みも持っている。Toolkitを利用すると、次のようなXAMLコードを記述できる。EventToCommand」(英文)より抜粋。BorderコントロールのTappedイベントをコマンド・プロパティに変換し、それに「Main.NavigateToArticleCommand」というコマンド・オプジェクトをバインドしている。まとめICommandインターフェイスを実装したコマンド・オブジェクトを作成すれば、原理的にはコントロールのイベントとコードビハインドのイベント・ハンドラを分離してコマンド・オブジェクトをバインドできる。全てを自前で実装するのは手間が掛かるため、MVVMフレームワークの利用を検討するとよい。ICommandインターフェイスの実装例は、次のドキュメントも参考になる。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。