WPFのコマンドを5ステップで書く(RoutedCommand編)
WPFではコマンドを使いましょう!
ボタンなどには抽象的な動作を関連づけましょう!
とよく言われます。しかし、WPFのコマンドとやらはなんか面倒です。
正直「Clickイベントでいいじゃん。」とか思ったりするわけです。
ということで今回はできるだけ簡単にコマンドで処理を実行させられるようにしてみたいと思います。
ICommandインターフェースを使わず、RoutedCommandクラスを使いました。
目次
なぜコマンドなのか。
まぁ、言われてみればボタンのClickイベントに直接処理を記述した場合、
- 同じ処理を別のボタンから呼び出すときに、
- 一旦処理をメソッドに括りだして、
- 両方のボタンからそのメソッドを呼ぶ。
とかやるわけですから、「最初から分けとけばいいじゃん」的な発想にはそこそこ納得できます。
しかし、しかしそれでも、ICommandやらRoutedCommandやらRoutedUICommandやらExecuteやらCanExecuteやら横文字ばっかでてきて、日本人には理解しにくいことこの上ないのです。
ここではなるべく簡単にコマンドで動作を実装する努力をしてみます。
5ステップで書いてみよう。
基本は5ステップです。
- RoutedCommandを宣言
- インスタンスのCommandBindingsにコマンドを追加するメソッドを作る
- コンストラクタで2を呼ぶ
- XAMLのルート要素にxmlns宣言を追加
- ボタンのCommandにコマンドを設定
1.RoutedCommandを宣言
readonlyかつstaticで宣言するのがお決まりらしいです。変数名はコマンド名と一緒にしましょう。
1 2 |
public readonly static RoutedCommand DoAction = new RoutedCommand("DoAction", typeof(MainWindow)); |
RoutedCommandのコンストラクタの引数は以下の2つ。
1.コマンド名(変数名と同じにする)
2.コマンドを登録する型(普通はそのクラス)
ちなみにRoutedCommandの代わりにRoutedUICommandを使ってもOKです。違いはコマンドを説明する文字列を設定できるだけです。
2.インスタンスのCommandBindingsにコマンドを追加するメソッドを作る
こんな感じ。コマンドが複数ある場合はどんどん同じようにAddする。
1 2 3 4 |
private void initCommandBindings() { this.CommandBindings.Add(new CommandBinding(DoAction, (s, e) => { /* some actions */ }, (s, e) => e.CanExecute = true)); } |
ちなみにこのコマンドバインディングはXAMLでも可能ですが、Executedイベントなどの実装がめんどくさいのと、Expression Blendでの自動生成ができないので、いっそVisual Studioで▲のようなメソッドを書いたほうが速いし、イベントハンドラとの関連性もわかりやすいです。
3.コンストラクタで2を呼ぶ
これは下記のように▲のメソッドをコンストラクタから呼ぶだけです。
1 2 3 4 5 |
public MainWindow() { this.InitializeComponent(); initCommandBindings(); } |
4.XAMLのルート要素にxmlns宣言を追加
XAML側からこのDoActionを認識するためにローカルの名前空間を追加する。
1 |
xmlns:local="clr-namespace:WpfCommandTest" |
XAMLの最初のほうのに他のxmlns宣言が並んでいるはずですので、そこに追加しましょう。
5.ボタンのCommandにコマンドを設定
ButtonやMenuItemなど、Commandが設定できるコントロールのCommandに{x:static local:アクション名}を追加します。Blendでも自動でできないので、カスタム式…で書くか、XAMLを直接書くかしかありません。コピペしましょう。
1 |
<Button Command="{x:Static local:MainWindow.DoAction}"/> |
以上です。
これで、ボタンを押したときに手順2で設定した処理が実行されるはずです。
この方法の問題点
C#(コードビハインド)側はまぁ、それなりにすっきりしていますが、XAML側がイマイチです。いちいちローカルの名前空間を宣言するのも煩雑ですし、コマンド定義もBlendからできないのが残念です。
このあたり、「コマンドを使え」というのなら、Blend側でももっと簡単にできるようにしてほしいところです。
最後までお読みいただきありがとうございました m(_ _)m