【问题标题】:Using multiple Actions in Action<object> list在 Action<object> 列表中使用多个操作
【发布时间】:2018-04-13 12:37:04
【问题描述】:

我正在学习更多关于使用ICommand 接口以及如何通过我创建的RelayCommand 类执行命令的知识。

首先,我对我想要实现的目标进行了一些研究,但我找不到任何可以帮助我的东西,或者我真的不知道如何搜索我想要做的事情。另外,我对 C# 理论的了解也不是很好,所以这也不利于我。

基本上,我试图将多个操作发送到我的RelayCommand 构造函数,然后遍历List&lt;Action&lt;object&gt;&gt; 集合中的所有操作并一一执行。这是我的代码:

RelayCommand 类构造函数

public RelayCommand(Predicate<object> canExecute, List<Action<object>> actions)
{
    _canExecute = canExecute;

    foreach (var action in actions)
        _execute = action;
}

然后是我的 ViewModel

中的命令属性
private ICommand _updateExternals;
public ICommand UpdateExternals
{
    get
    {
        if (_updateExternals == null)
        {
            _updateExternals = new RelayCommand(
                x => CanExecute,
                Updater.UpdateExternals(this));//Here is where I am stuck
        }
        return _updateExternals;
    }
}

我知道,从其他示例中,如果我只需要通过单个 Action 而不是操作列表,则代码将如下所示:x =&gt; Updater.UpdateExternals(this)); 并且它会起作用,但只要我有一个动作列表作为我卡住的参数。

所以,如果您还没有猜到,我的问题是:如何通过多个 Action 向我的 RelayCommand 类发送?

任何正确方向的帮助将不胜感激,谢谢!

编辑:这是我完整的 RelayCommand 课程,让我更多地了解我在做什么。

public class RelayCommand : ICommand
{
    private Predicate<object> _canExecute;
    private Action<object> _execute;

    public RelayCommand(Predicate<object> canExecute, List<Action<object>> actions)
    {
        _canExecute = canExecute;
        foreach (var action in actions)
            _execute = action;
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }

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

【问题讨论】:

  • 为什么Predicate&lt;object&gt;(类似于Func&lt;object, bool&gt;)叫canExecute?遍历actions 并将它们中的每一个(不调用它们)分配给同一个字段,这就是你对foreach (var action in actions) _execute = action; 所做的,似乎没有用?我不太了解你的工作。
  • Updater.UpdateExternals 长什么样子?
  • 只需在列表中循环您的元素并调用委托:foreach(a in myList) a(myParams); 但是为什么您在 RelayCommand-constructor 中的每次迭代中都会过度使用 _execute-字段?
  • @JeppeStigNielsen 感谢 Jeppe 的评论。我已经编辑了我的问题,以便它可以更多地解释我在做什么。
  • @Evk 这可能是我试图调用的任何方法。我已经编辑了我的问题,因此它可以帮助更多地了解我正在尝试做的事情。感谢您的评论。

标签: c# action icommand


【解决方案1】:

要解决您的问题,请在构造函数中使用params

public class RelayCommand : ICommand {
    private Predicate<object> _canExecute;
    private Action<object>[] _execute;

    public RelayCommand(Predicate<object> canExecute, params Action<object>[] actions) {
        _canExecute = canExecute;
        _execute = actions;
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter) {
        return _canExecute(parameter);
    }

    public void Execute(object parameter) {
        foreach (var action in _execute)
            action(parameter);
    }
}

然后你可以像往常一样创建这样的命令:

_updateExternals = new RelayCommand(
    x => CanExecute,
    x => Updater.UpdateExternals(this));//Here is where I am stuck

当你需要传递多个动作时:

_updateExternals = new RelayCommand(
    x => CanExecute,
    x => Updater.UpdateExternals(this),
    x => Updater.DoSomethingElse(this));

【讨论】:

    【解决方案2】:

    你的类需要有一个你想要执行的动作的列表,所以把它作为一个字段添加到你的类中,然后在构造函数中设置它。 然后在您的 Execute 方法(接口实现)中,您只需遍历操作并一个接一个地调用它们。

    public class RelayCommand : ICommand
    {
        private Predicate<object> _canExecute;
        private List<Action<object>> _executes;
    
        public RelayCommand(Predicate<object> canExecute, List<Action<object>> actions)
        {
            _canExecute = canExecute;
            _executes = actions;
        }
    
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    
        public bool CanExecute(object parameter)
        {
            return _canExecute(parameter);
        }
    
        public void Execute(object parameter)
        {
            foreach(e in _executes )
            {            
               e(parameter);
            }
        }
    }
    

    您的原始代码所做的是将单个操作引用一遍又一遍地分配给构造函数参数中的每个操作,因此您的类只会在调用 Execute 时执行列表中的最后一个操作。

    请记住 ActionAction&lt;T&gt; 或多或少只是对某些方法的引用,命名或匿名 (lambda)。

    【讨论】:

    • 感谢辛德里的回答。我只需要提一下,我目前的问题不在于我的RelayCommand 课程,而是我的ViewModel 中的编码。
    • 啊,是的,您必须将多个操作包装在一个列表中,例如 new List&lt;Action&lt;object&gt;&gt;(){ commaSeparatedActionReferencesWithOutParenthesis }
    • 您也可以使用委托组合来代替List&lt;&gt;。例如 public RelayCommand(Predicate&lt;object&gt; canExecute, List&lt;Action&lt;object&gt;&gt; actions) { _canExecute = canExecute; foreach (var a in actions) { _multiExecute += a; } } 请注意,Action&lt;&gt; 与任何其他 .NET 委托类型一样,支持“多播”委托实例。
    • 另一个答案@Evk 也可以,因为params 意味着它可以接受任意数量的相同类型的参数,用逗号分隔。
    • 感谢您在@SindriJóelsson 的回答中对单个动作参考的解释。它帮助我更多地了解我做错了什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-10
    相关资源
    最近更新 更多