При желании передать параметр типа T в действие - PullRequest
0 голосов
/ 09 января 2019

У меня есть класс с именем RelayCommand, который наследует интерфейс 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 
}

Я использую этот класс для выполнения команд в приложении, и иногда мне нужно выполнить Action s, передав параметр в XAML. Проблема в том, что эта передача параметров является необязательной, но я не могу найти решение, которое бы соответствовало тому, что я делаю Например, у меня есть эти три команды, которые в основном делают то же самое. Я устанавливаю PriorityLevel (enum значение) для объекта через пользовательский интерфейс и, в зависимости от того, на каком элементе управления выполняется щелчок, я выполняю один из следующих трех методов:

    /// <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. Затем я потребляю Action s вот так:

    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>

Я нашел множество ответов по этому поводу, но ни один из них, казалось, не делал использование параметров необязательным.

Как мне настроить класс RelayCommand в соответствии со своими потребностями?

Заранее спасибо за помощь.

1 Ответ

0 голосов
/ 09 января 2019

Самое простое изменение в вашем коде - просто взять параметр 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)
    {
        //...//
    }
}
...