ここでは、MVVM パターンの要となるデータバインディング機能を実現するための ICommand インターフェースについて紹介します。
MVVM パターンでは、アプリケーション内部構造を下図のように Model、View、ViewModel の 3 つに大別します。
このとき、View と ViewModel でデータを連携する手段としてデータバインディング機能を用います。
MVVM パターンでは、ボタンを押すなどの View が受け取ったユーザ指示を ViewModel に通知します。
このとき、ViewModel にその指示を通知するために用いるのが ICommand インターフェースです。
逆に、その指示が実行可能かどうかを判別し、その可否を通知するのも ICommand インターフェースの役割で、
これは ViewModel から View に通知する必要があります。
ICommand インターフェースのメンバは次のようになります。
Execute() メソッドによってコマンドの実行をおこないます。また、CanExecute() メソッドでコマンドが実行可能かどうかを判別します。
実行可能かどうかに影響する変更があった場合には、CanExecuteChanged イベントを発行する必要があります。
それでは、ボタンを押すことによって実行されるコマンドを、データバインディング機能を用いて ViewModel 側に記述する方法を紹介します。
コマンドを使用するには、ICommand インターフェースを実装したプロパティが必要になります。
YKToolkit.Controls.dll を利用することで ICommand インターフェースが既に実装されたクラスを扱うことができますが、
ここでは敢えて ICommand インターフェースを自前で実装して、その内部構造を知ってもらおうと思います。
DelegateCommand クラスという ICommand インターフェースを実装するクラスを次のように定義します。
ICommand インターフェースは、実際にコマンドの内容を実施する Execute() メソッドと、
このコマンド自体が実行可能かどうかを判別するための CanExecute() メソッドを実装する必要があります。
コマンドの内容や実行可能かどうかの条件をここで固定させる必要はないため、_execute および _canExecute という private フィールドを用意し、
コマンドの中身や実行可能判別の処理を外部から指定できるようにしています。
実行可能かどうかに影響するような変更があった場合、RaiseCanExecuteChanged() メソッドを呼び出すことで、
CanExecuteChanged イベントを発行し、その変更を View 側に伝えます。
ここでは、CanExecuteChanged イベントを CommandManager.RequerySuggested イベントに委任しているため、
こちらのイベントを発生させることで CanExecuteChanged イベントを発生させています。
ただし、同じ View(ViewModel)に複数のコマンドが存在し、この RaiseCanExecuteChanged() メソッドを呼び出した場合、
すべてのコマンドに対して再評価がおこなわれるため、各コマンドに対して呼ぶ必要はありません。
このことから、RaiseCanExecuteChanged() メソッドは static なメソッドとして定義しています。
具体例として、こちらのページで作成した MainViewModel のサンプルコードに、ClearCommand プロパティを次のように追加します。
get アクセサによるプロパティ値取得タイミングで、private フィールドである clearCommand 変数が null のときのみ DelegateCommand クラスをインスタンス化しています。
コマンドの中身は Text プロパティを空にするという処理で、Text プロパティが既に空である場合は実行不可であるという判別をおこなっています。
次に、このプロパティを参照するように、MainView を次のように変更します。
コンパイル、実行すると、起動直後は Text プロパティが空であるため、
Button コントロールの Command プロパティの実行可能判別処理によって Button コントロールの IsEnabled プロパティが false となっています。
TextBox コントロールに任意の文字列を入力して Text プロパティに文字列が設定されると、
Button コントロールの実行可能判別処理によって Button コントロールの IsEnabled プロパティが true となり、ボタンを押せるようになります。
また、ボタンを押すと ClearCommand のコマンド実行処理がおこなわれ、Text プロパティが空になるため、TextBox コントロールのテキストが空になります。
| |
(a) テキストを入力するとボタンが有効になる | (b) ボタンを押すと TextBox コントロールが空になる |
Fig. 2 : ClearCommand プロパティがバインディングされた画面