WPF の MVVM なプログラムを書いていて、引数を受け取るコマンドが必要になったので、以前書いた ViewModelBase の RelayCommand を拡張しました。その内容を書いておきます(次の記事を書くのに必要でもあったり 🙂 )。
拡張前のコマンド作成は次のようにしていました。
private void fooExecute()
{
}
private Icommand _fooCommand;
public ICommand FooCommand = new RelayCommand
{
get
{
if (_fooCommand == null)
_fooCommand = new RelayCommand(
param => fooExecute()
);
return _fooCommand;
}
}
引数を受け取るコマンドは次のようにして作成します。
private void barExecute(int id)
{
// id を使って何かをする
}
private RelayCommand<int> _barCommand;
public ICommand BarCommand
{
get
{
if (_barCommand == null)
_barCommand = new RelayCommand<int>(barExecute);
return _barCommand;
}
}
XAML での設定方法(ViewModel 側に引数を供給する int な Id プロパティがあることを前提)。
<Button
Content="引数を処理するコマンド"
Command="{Binding BarCommand}"
CommandParameter="{Binding Id}" />
ついでに、引数を受け取らないコマンドも同様の形式で作成できるようにしました。
private void bazExecute()
{
}
private ICommand _bazCommand;
public ICommand BazCommand
{
get
{
if (_bazCommand == null)
_bazCommand = new RelayCommand(bazExecute);
return _bazCommand;
}
}
CanExecute の設定方法は、今までのものと同様です(変更はありません)。コマンドと同じ形式で指定したい場合は、CanExecute をプロパティではなくメソッドで作成(private bool bazCanExecute(object param) { return 条件式 })すれば同じ形式で指定できます。
ということで、RelayCommand のソースです。
using System;
using System.Windows.Input;
namespace MakCraft.ViewModels
{
/// <summary>
/// デリゲートを呼び出すことによって、コマンドを他のオブジェクトに中継する。CanExecute メソッドの既定値は 'true'。
/// </summary>
public class RelayCommand : ICommand
{
#region fields
private readonly Action<object> _executeOld;
private readonly Action _execute;
private readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructor
/// <summary>
/// 実行可否判定のないコマンドを作成
/// </summary>
/// <param name="execute"></param>
[Obsolete("RelayCommand(Action execute) または RelayCommand(Action<T> execute) を使用してください。")]
public RelayCommand(Action<object> execute) : this(execute, null) { }
/// <summary>
/// 実行可否判定のないコマンドを作成
/// </summary>
/// <param name="execute"></param>
public RelayCommand(Action execute) : this(execute, null) { }
/// <summary>
/// コマンドを作成
/// </summary>
/// <param name="execute"></param>
/// <param name="canExecute"></param>
[Obsolete("RelayCommand(Action execute, Predicate<object> canExecute) または RelayCommand(Action<T> execute, Predicate<object> canExecute) を使用してください。")]
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("param: execute");
_executeOld = execute;
_canExecute = canExecute;
}
/// <summary>
/// コマンドを作成
/// </summary>
/// <param name="execute"></param>
/// <param name="canExecute"></param>
public RelayCommand(Action execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("param: execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructor
#region ICommand Members
/// <summary>
/// 現在の状態でこのコマンドを実行できるかどうかを判断します。
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
/// <summary>
/// コマンドを実行するかどうかに影響するような変更があった場合に発生するイベントです。
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// コマンドの起動時に呼び出されるメソッドです。
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
if (_execute != null)
_execute();
else
_executeOld(parameter);
}
#endregion // ICommand Members
}
/// <summary>
/// デリゲートを呼び出すことによって、コマンドを他のオブジェクトに中継する。CanExecute メソッドの既定値は 'true'。
/// </summary>
public class RelayCommand<T> : ICommand
{
#region fields
private readonly Action<T> _execute;
private readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructor
/// <summary>
/// 実行可否判定のないコマンドを作成
/// </summary>
/// <param name="execute"></param>
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// コマンドを作成
/// </summary>
/// <param name="execute"></param>
/// <param name="canExecute"></param>
public RelayCommand(Action<T> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("param: execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructor
#region ICommand Members
/// <summary>
/// 現在の状態でこのコマンドを実行できるかどうかを判断します。
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
/// <summary>
/// コマンドを実行するかどうかに影響するような変更があった場合に発生するイベントです。
/// </summary>
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
/// <summary>
/// コマンドの起動時に呼び出されるメソッドです。
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion // ICommand Members
}
}
今までの形式のものは Obsolete 指定しています。
ソースコードのダウンロードページを作成したので、一式をダウンロードしたい方はご利用ください。