Xamlで使えるようになりたいCommand
最初見たときは「イベントでええやん」と思った Command だけど、MVVM を勉強したころから「これ使えるようになった方がいいかも」と気づいた。正直、全然理解しきれてないけど書いてく。
目次
自分なりの理解になってしまうが、Command がなぜ必要なのかまとめる。(自分なりというのはあまり好きじゃないけど)
もしもなんか暇でここを読んでいる博識な方がいたら指摘お願いしたいくらい。 存在意義は単刀直入に言って、「View からコードを分離するため」に Command がある。
Command と イベントとの決定的な違いは、実装している場所である。
イベントは必ず内部コード(xaml.cs)側にコードを実装する。
しかし、Command は View Model 側にコードを実装する。 Command は View Model 側に実装されるため、「View(xaml.cs)には一切コードを追加しない」がボタンを押すとちゃんといろんな処理がされる、といったことも可能になる。 そんなに使ったことがないのだけど、Command はバインディングして使う。 こんな感じで。とっても普通。 また、下記のように、1つだけだが引数の指定が可能。1つしかダメな理由は後述の「 Command の構成」を参照。
ボタンを押すと 1 が指定のコントロールに追加される Command 例。 バインディングして使うので、もし同じ動きをしてほしいボタン等あれば Command をバインディングさせるだけで実現できる。
値を変えたかったら引数を指定してやればいい。
やってることのイメージは、1つのイベントを複数のコントロールに割り当ててる感じ。
そう考えると、Command とイベントの違いは本当に「実装している場所」くらいのイメージでいい(と思う)。 Command は ICommand インターフェースを継承して使う。
その時必要になるのは以下の3つ。 上記のうち、 CanExecute と Execute をコンストラクタとかで入れてあげれば Command 完成。 サンプルは以下のとおり。
これを View Model 側でインスタンスを作ってやって、View Model 側にある関数を CanExecute や Execute に渡せばいい。Command の存在意義
Command の使い方
<Grid DataContext="{StaticResource viewModel}">
<Button Context="キャンセル" Command="{Binding CancelCommand}"/>
</Grid>
<Button Content="1" Command="{Binding AddCharacterCommand}" CommandParameter="1"/>
Command の構成
項目
説明
CanExecuteChanged
CanExecute 状態が変更されたときに発生するイベント(のはず)。これを発生させると、CanExecute メソッドの結果によってこの Command が割り当てられたコントロールが操作できなくなる( IsEnable が false )。
CanExecute
現在の状態で Command が実行可能かどうかを決定するメソッド。
Execute
コマンドが起動される際に呼び出すメソッド。
public class DelegateCommand : ICommand
{
Action<object> mExecute;
Func<object, bool> mCanExecute;
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter) => mCanExecute(parameter);
public void Execute(object parameter) => mExecute(parameter);
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
mExecute = execute;
mCanExecute = canExecute;
}
/// <summary>
/// 既定のcanExecute代入するコンストラクタ
/// </summary>
public DelegateCommand(Action<object> execute)
{
mExecute = execute;
mCanExecute = new Func<object, bool>((param) => { return true; });
}
}