可选择将 T 类型的参数传递给 Action

Optionally pass a parameter of type T to an Action

我有一个名为 RelayCommand 的 class,它继承了如下定义的 ICommand 接口:

/// <summary>
/// Base command that executes an <see cref="Action"/>.
/// </summary>
public class RelayCommand : ICommand
{
    #region Members

    // The Action to run.
    private Action mAction;

    #endregion

    #region Events

    /// <summary>
    /// Event fired when the value of <see cref="CanExecute(object)"/> changes.
    /// </summary>
    public event EventHandler CanExecuteChanged = (sender, e) => { };

    #endregion

    #region Constructor

    /// <summary>
    /// Default <see cref="RelayCommand"/> constructor.
    /// </summary>
    public RelayCommand(Action action)
    {
        mAction = action;
    }

    #endregion

    #region Command Methods

    /// <summary>
    /// A <see cref="RelayCommand"/> can always be executed.
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return true;

    }

    /// <summary>
    /// Executes the <see cref="Action"/> of the command.
    /// </summary>
    /// <param name="parameter"></param>
    public void Execute(object parameter)
    {
        mAction();
    }

    #endregion 
}

我使用此 class 在整个应用程序中执行命令,有时我需要执行 Actions 在 XAML 中传递参数。问题是这个参数传递是可选的,但我找不到适合我正在做的事情的解决方案。例如,我有这三个命令,它们基本上做同样的事情。我通过 UI 将 PriorityLevelenum 值)设置为对象,并根据单击的控件执行以下三种方法之一:

    /// <summary>
    /// What to do when the priority of the task is set to <see cref="PriorityLevel.Low"/>
    /// </summary>
    private void OnSetLowPriorityCommand()
    {
        Priority = PriorityLevel.Low;
        PriorityGridWidth = 10;
        PriorityFlagOpacity = 0;
        mIsPriorityChanged = true;
    }

    /// <summary>
    /// What to do when the priority of the task is set to <see cref="PriorityLevel.Medium"/>
    /// </summary>
    private void OnSetMediumPriorityCommand()
    {
        Priority = PriorityLevel.Medium;
        PriorityGridWidth = 10;
        PriorityFlagOpacity = 0;
        mIsPriorityChanged = true;
    }

    /// <summary>
    /// What to do when the priority of the task is set to <see cref="PriorityLevel.High"/>
    /// </summary>
    private void OnSetHighPriorityCommand()
    {
        Priority = PriorityLevel.High;
        PriorityGridWidth = 10;
        PriorityFlagOpacity = 0;
        mIsPriorityChanged = true;
    }

如你所见,除了第一行的方法,其余的都是一样的,但我认为如果我只保留一个调用的方法会更好,例如SetPriorityCommand ,通过 switch 或其他任何方式,设置正确的 PriorityLevel 值。然后我像这样消耗 Actions:

    SetLowPriorityCommand = new RelayCommand(OnSetLowPriorityCommand);

无论如何,在其他情况下我执行 Action 而无需传递参数。

最后,在 XAML 我需要执行这样的命令:

    <Border.InputBindings>
        <MouseBinding MouseAction="LeftClick"
                      Command="{Binding SetLowPriorityCommand}"
                      CommandParameter="{Binding Source={x:Static core:PriorityLevel.Low}}"/> <!-- NOT ALWAYS NECESSARY -->
    </Border.InputBindings>

我找到了很多关于这个的答案,但 none 似乎使用可选参数。

如何调整 RelayCommand class 以满足我的需要?

提前感谢您的帮助。

对代码最简单的更改就是采用 object 参数并在调用方法时转换该参数。否则,您可以在网上搜索并找到 RelayCommand<T> 的大量实现,但这里有一个仅使用 object 参数的示例,无论您是否使用该参数。

public class RelayCommand : ICommand
{
    private Action<object> mAction;

    public event EventHandler CanExecuteChanged = (sender, e) => { };

    public RelayCommand(Action<object> action)
    {
        mAction = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;

    }

    public void Execute(object parameter)
    {
        mAction(parameter);
    }
}

public class ViewModel
{

    //ignore the argument
    private RelayCommand SetLowPriorityCommand { get => new RelayCommand(_ => SetLowPriority()); }

    //cast and use the argument
    private RelayCommand SetPriority { get => new RelayCommand(priority => SetPriority((int)priority)); }


    private void SetLowPriority()
    {
        //....///
    }

    private void SetPriority(int priority)
    {
        //...//
    }
}