Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2007年11月15日]

XAMLで自作コマンド

2007年11月16日 07:49更新 筆者:K.Ktouth

XAMLとWPFの勉強中……
画面設計は試行錯誤しつつ進行中。
が、メニューのイベントハンドラのバインドさせるのに丸一日かかりました(笑)

以下、自分メモ。

1: メニュー構造はXAMLで、ハンドラはC#で。

Delphi(VCL)ではだいぶん前に実装されていたアクション機能。WPFでようやく実装された模様。
で、コレによってXAML(ウィンドウ構成)とC#(実装)が明確に分けられるように。
一般的なアプリケーションで使用される用なコマンドは標準で準備されているので、あとはそのコマンドに対応するイベントハンドラをつくってコマンドと対応づけるだけという、簡単操作。

public partial class MainWindow : Window
{
 public MainWindow() {
   :
   :
  CommandBinding bind = new new CommandBinding(ApplicationCommands.Close, DoClose);
  this.CommandBindings.Add(bind);
 }

 private void DoClose(object sender, ExecutedRoutedEventArgs e)
 {
  Close();
 }
}

CommandBindingのコマンドとイベントハンドラを引数にインスタンスを生成。
WPFのイベントは投げられた要素だけでなく、その要素の親要素にも伝播していく(ルートは当然Window)ので、今回は生成したインスタンスをWindowのCommandBindingsに登録。
これで、標準コマンド[ ApplicationCommands.Close ]の実装を宣言できたので、次はXAML側での定義。

<Menu>
 <MenuItem Header="ファイル(_F)">
  <MenuItem Header="終了(_X)" Command="Close" />
 </MenuItem>
</Menu>

今回はシンプルなメニューで定義。標準で準備されているコマンドは文字表記で簡単に参照可能。
ちなみにコマンドに実装がバインドされていない場合、自動的にdisabledになる。

2: 独自のコマンドの作成と、使用方法

しかし、バージョン情報の表示など、標準コマンドに適当なものがない場合、コマンドを自作する必要がある。
# もちろんコマンドを使用せず、メニューなどに直接イベントハンドラを登録する方法もある。

public partial class MainWindow : Window
{
 public readonly static RoutedUICommand About;
 static MainWindow()
 {
  About = new RoutedUICommand("バージョン情報を表示します", "About", typeof(MainWindow));
 }

 public MainWindow() {
   :
   :
  this.CommandBindings.Add(new CommandBinding(MainWindow.About, delegate(object sender, ExecutedRoutedEventArgs e)
  {
   MessageBox.Show("バージョン情報");
  }));
 }

まず、コマンドの生成。特定クラスのreadonly静的変数として定義するのが一般的らしい。
readonly属性がついているので、当然クラスコンストラクタを準備してその中で初期化する。やりかたは依存プロパティのキー作成とほぼ一緒。
イベントハンドラのバインドは標準コマンドへのバインドと同じ。単純なものなら上記のような無名デリゲートを使うほうが早いかも。

<Window x:Class="Example.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:app="clr-namespace:Example">
   :
   :
  <Menu>
   <MenuItem Header="ヘルプ(_F)">
    <MenuItem Header="バージョン情報(_A)" Command="{x:Static app:MainWindow.About}" />
   </MenuItem>
  </Menu>
   :
   :
</Window>

ちょっと追加処理が必要なのがXAML側。
まず、標準のままでは独自コマンドが認識できない。名前空間の修飾が必要なので、ルート要素にxmlns:app名前空間属性を追加。
次にコマンドの参照。標準コマンドと違い、stringからの変更はきかないようなのでコード定義に頼る。

アプリケーションでの実装機能などを呼び出す事はよくあると思うので、名前空間はさっさと追加しておくのが一番らしい。

本日のリンク元
アンテナ
その他のリンク元
検索