for WPF developers
Home Profile Tips 全記事一覧

DelegateCommand クラス

(2017/03/07 15:37:04 created.)

ボタンの Command プロパティなどとデータバインディングするために、ICommand インターフェースを実装した DelegateCommand クラスを次のように定義します。

DelegateCommand.cs
  1. using System;
  2. using System.Windows.Input;
  3.  
  4. /// <summary>
  5. /// ICommand インターフェースを実装したコマンド用のクラスを表します。
  6. /// </summary>
  7. public class DelegateCommand : ICommand
  8. {
  9.     #region private フィールド
  10.     /// <summary>
  11.     /// コマンドを実行するためのメソッドを保持します。
  12.     /// </summary>
  13.     private Action<object> _execute;
  14.  
  15.     /// <summary>
  16.     /// コマンドの実行可能性を判別するためのメソッドを保持します。
  17.     /// </summary>
  18.     private Func<object, bool> _canExecute;
  19.     #endregion private フィールド
  20.  
  21.     #region コンストラクタ
  22.     /// <summary>
  23.     /// 新しいインスタンスを生成します。
  24.     /// </summary>
  25.     /// <param name="execute">コマンドを実行するためのメソッドを指定します。</param>
  26.     public DelegateCommand(Action<object> execute)
  27.         : this(execute, null)
  28.     {
  29.     }
  30.  
  31.     /// <summary>
  32.     /// 新しいインスタンスを生成します。
  33.     /// </summary>
  34.     /// <param name="execute">コマンドを実行するためのメソッドを指定します。</param>
  35.     /// <param name="canExecute">コマンドの実行可能性を判別するためのメソッドを指定します。</param>
  36.     public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
  37.     {
  38.         this._execute = execute;
  39.         this._canExecute = canExecute;
  40.     }
  41.     #endregion コンストラクタ
  42.  
  43.     #region ICommand のメンバ
  44.     /// <summary>
  45.     /// コマンドの実行可能性を判別します。
  46.     /// </summary>
  47.     /// <param name="parameter">この処理に対するパラメータを指定します。</param>
  48.     /// <returns>コマンドが実行可能である場合に true を返します。</returns>
  49.     public bool CanExecute(object parameter)
  50.     {
  51.         return this._canExecute != null ? this._canExecute(parameter) : true;
  52.     }
  53.  
  54.     /// <summary>
  55.     /// コマンドの実行可能性が変更されたときに発生します。
  56.     /// </summary>
  57.     public event System.EventHandler CanExecuteChanged
  58.     {
  59.         add { CommandManager.RequerySuggested += value; }
  60.         remove { CommandManager.RequerySuggested -= value; }
  61.     }
  62.  
  63.     /// <summary>
  64.     /// コマンドを実行します。
  65.     /// </summary>
  66.     /// <param name="parameter">この処理に対するパラメータを指定します。</param>
  67.     public void Execute(object parameter)
  68.     {
  69.         if (this._execute != null)
  70.             this._execute(parameter);
  71.     }
  72.     #endregion ICommand のメンバ
  73. }

実際に処理する内容や、実行可能かどうかを判別するための処理はコマンドによって異なるため、これらの処理を直接このクラス内で記述するのではなく、private なフィールドである _execute と _canExecute 変数で保持します。

DelegateCommand クラスの使用例は次のようになります。

SampleViewModel.cs
  1. /// <summary>
  2. /// DelegaeCommand クラスの使用例を示すためのクラスを表します。
  3. /// </summary>
  4. public class SampleViewModel : NotificationObject
  5. {
  6.     private double _lhs;
  7.     /// <summary>
  8.     /// 割られる数を取得または設定します。
  9.     /// </summary>
  10.     public double Lhs
  11.     {
  12.         get { return this._lhs; }
  13.         set { SetProperty(ref this._lhs, value); }
  14.     }
  15.  
  16.     private double _rhs;
  17.     /// <summary>
  18.     /// 割る数を取得または設定します。
  19.     /// </summary>
  20.     public double Rhs
  21.     {
  22.         get { return this._rhs; }
  23.         set { SetProperty(ref this._rhs, value); }
  24.     }
  25.  
  26.     private double _answer;
  27.     /// <summary>
  28.     /// 計算結果を取得します。
  29.     /// </summary>
  30.     public double Answer
  31.     {
  32.         get { return this._answer; }
  33.         private set { SetProperty(ref this._answer, value); }
  34.     }
  35.  
  36.     private DelegateCommand _divideCommand;
  37.     /// <summary>
  38.     /// 割り算コマンドを取得します。
  39.     /// </summary>
  40.     public DelegateCommand DivideCommand
  41.     {
  42.         get
  43.         {
  44.             return this._divideCommand ?? (this._divideCommand = new DelegateCommand(
  45.             _ =>
  46.             {
  47.                 // ここにはコマンドとして実行する処理を記述します。
  48.  
  49.                 // 割り算をおこないます。
  50.                 this.Answer = this.Lhs / this.Rhs;
  51.             },
  52.             _ =>
  53.             {
  54.                 // ここには実行可能性を判別する処理を記述します。
  55.  
  56.                 // 割る数がゼロ以外のときに割り算が実行できます。
  57.                 return this.Rhs != 0.0;
  58.             }));
  59.         }
  60.     }
  61. }

DelegateCommand クラスのコンストラクタでは、第一引数にコマンドとして実行する処理を、第二引数としてコマンドの実行可能判別をおこなう処理を指定します。使用例のように、ラムダ式による表現を用いる方法が一般的に使われます。常に実行可能であるコマンドの場合は、コンストラクタの第二引数を省略することができます。

上記のラムダ式では入力引数を使用しないので "_" という変数名としていますが、CommandParaneter を受け取る場合は、適宜変数名を変更したほうが良いでしょう。