【问题标题】:Commands using Action<> and Func<>使用 Action<> 和 Func<> 的命令
【发布时间】:2013-04-24 08:14:33
【问题描述】:

我正在处理MVVM Survival Guide for Enterprise Architectures in Silverlight and WPF 并在命令部分遇到了障碍。具体来说,它基于 Action 和 Func 创建一个命令。在我应该“构建并运行应用程序”的地方,我却得到了编译错误。

命令内容:

public class Command : ICommand
{
  private readonly Action<object> _execute;
  private readonly Func<object, bool> _canExecute;
  public Command(Action<object> execute, Func<object, bool> canExecute)
  {
    _execute = execute;
    _canExecute = canExecute;
  }
 public void Execute(object parameter)
  {
    _execute(parameter);
  }
  public bool CanExecute(object parameter)
  {
    return (_canExecute == null) || _canExecute(parameter);
  }
  ...
}

方法调用的东西:

private Command _showDetailsCommand;
public Command ShowDetailsCommand
{
  get 
  { 
      return _showDetailsCommand 
             ?? (_showDetailsCommand 
                = new Command(ShowCustomerDetails, IsCustomerSelected));
   }
}
public void ShowCustomerDetails()
{
  if (!IsCustomerSelected()){
    throw new InvalidOperationException("Unable to display customer details. "
                + "No customer selected.");
  }
  CustomerDetailsTabViewModel customerDetailsViewModel = 
            GetCustomerDetailsTab(SelectedCustomerID);
  if (customerDetailsViewModel == null)
  {
    customerDetailsViewModel 
         = new CustomerDetailsTabViewModel
               (_dataProvider, 
                SelectedCustomerID);
    Tabs.Add(customerDetailsViewModel);
  }
  SetCurrentTab(customerDetailsViewModel);
}
private bool IsCustomerSelected()
{
  return !string.IsNullOrEmpty(SelectedCustomerID);
}

new Command(ShowCustomerDetails, IsCustomerSelected)) 位下方出现蓝色波浪线,并带有“Northwind.Application.Command.Command(System.Action&lt;object&gt;, System.Func&lt;object, bool&gt;) 的最佳重载匹配有一些无效参数”。

当我尝试编译时,我收到上述错误,以及两条消息:

Argument 1: Cannot convert from method group to System.Action<object>
Argument 2: Cannot convert from method group to System.Func<object, bool>

现在,我对 Actions 和 Funcs 的了解比昨天更多,并且几乎可以通过将命令声明更改为:

private readonly Action _execute;
private readonly Func<bool> _canExecute;

并在整个代码中执行类似操作,但随后我收到一条错误消息,提示我没有正确实现 ICommand。

为了节省我的前额/最近的墙,有人可以告诉我我做错了什么以便我可以修复它,或者给定的(书)代码让我出错,所以我可以继续前进。

【问题讨论】:

  • 动作和函数都需要一个对象参数,但是你传入的方法没有任何参数。

标签: c# wpf mvvm icommand relaycommand


【解决方案1】:

那是因为

private bool IsCustomerSelected()
{
    return !string.IsNullOrEmpty(SelectedCustomerID);
}

类型不是Func&lt;object, bool&gt;,而是Func&lt;bool&gt;。它应该看起来像

private bool IsCustomerSelected(object param)
{
    return !string.IsNullOrEmpty(SelectedCustomerID);
}

您可以改用Predicate&lt;object&gt;,这至少对我来说更清楚,签名应该是什么样子。

【讨论】:

  • 这乍一看是有道理的,但与我的尝试相比,这似乎是另一种出路。那么我是否可以创建两个新方法来获取满足 Action 和 Func 的对象,然后简单地调用该方法的无参数版本来让一切运行?回答我自己的评论。是的。现在工作。非常感谢。
  • 此更改不允许运行书中的代码,带来的问题多于解决方案
  • @ГеннадийВанинНовосибирск 在没有争论的情况下进行良好的批评就像把手伸进正在运转的风扇一样有用。所以给我一些论据,让我们讨论一下。我知道我的解决方案可能不是最好的,但我想向他展示为什么他有问题,而不是他必须如何正确实施。像往常一样,有多种方法可以正确地做到这一点。我把它留给他,他将如何处理这些知识。
  • @DHN,你在写你的上一条评论之前检查过我的答案(用“粉丝”)吗?无论如何,请在那里查看我的response to you
  • 嗯,@ГеннадийВанинНовосибирск。如果您按照我在评论 #1 中的建议进行操作,它可以与本书的其余代码一起使用。您添加一个方法 IsCustomerSelected(object),并在该方法中返回对无参数方法的调用。这允许 IsCustomerSelected 的其余用法起作用。就目前而言,这本书自己的代码不允许它运行。
【解决方案2】:

将Command 类替换为下面的代码后,它应该是最重要的

public class Command : ICommand
{   //private readonly Action<object> _execute;
    private readonly Action _execute;

    //private readonly Func<object, bool> _canExecute;
    private readonly Func<bool> _canExecute;//instead of prev line 

    //public Command(Action<object> execute) 
    public Command(Action execute)//instead of prev line
      : this(execute, null)
    { }

    //public Command(Action<object> execute,
    public Command(Action execute,//instead of prev line 
    Func<bool> canExecute)//added instead of next line 
    //Func<object, bool> canExecute)
    {   _execute = execute;
        _canExecute = canExecute;
    }

    public void Execute(object parameter)
    {
        //_execute(parameter);
        _execute();//added instead of prev line 
    }
    public bool CanExecute(object parameter)
    {   return (_canExecute == null)
        //|| _canExecute(parameter);
        || _canExecute();//added instead of prev line 
    }
    public event EventHandler CanExecuteChanged = delegate { };
    public void RaiseCanExecuteChanged()
    {   CanExecuteChanged(this, new EventArgs());     }
}

在上述书中的代码上检查了这一点(第 205 页,第 5 章)

  • Vice R.,Shujaat Siddiqi M. - Silverlight 和 WPF 中企业架构的 MVVM 生存指南,PACKT Publishing,ISBN 978-1-84968-342-5,2012

这是本书正文中的错误/错字

真的,在本书的随附代码中,任何人都可以从Download the support files for this book 获得,正确的RelayCommand 类在本书的正文中被使用而不是Command 类,据此我在上面进行了更改Command类

顺便说一句,online errata to the book 中没有它


回复@DHN comment

将IsCustomerSelected()方法改为IsCustomerSelected(object param)会带来

ShowCustomerDetails 在下面的 sn-p 上(它在“方法调用的东西:”之后):

private Command _showDetailsCommand;

public Command ShowDetailsCommand
{
    get
    {
        return _showDetailsCommand ??
                (_showDetailsCommand =
                    new Command
                        (
                           ShowCustomerDetails,//error
                           IsCustomerSelected
                         )
                );
    }
}

错误:

需要一个带有 'void ShowCustomerDetails(object)' 签名的方法

因为ShowCustomerDetails() 是:

public void ShowCustomerDetails()
{
  if (!IsCustomerSelected())
     throw new InvalidOperationException("Unable to display customer details. "
     + "No customer selected.");
}

如果要更改后者ShowCustomerDetails(object param),这会带来更多的变化和更多的必要性,以便在每次连续更改时更改代码。

只需运行代码并尝试合并您的更改,看看它会调用什么

【讨论】:

  • 好的,你知道了。我没看到,ShowCustomerDetails() 也没有正确的签名。但也许 TO 是一个聪明的程序员,可以调整我的部分解决方案,这样一切都是正确的。 ;o) 好吧,我没有参考这本书,恕我直言,这不是问题,因为我没有它。但我不明白,为什么我应该有。
  • 我知道本书的下一部分涉及RelayCommand,并且我在必要时使用 d/l 代码提供帮助。但是,我想了解为什么它不起作用。我也知道并非每段书面代码都可以在页面外工作,所以我确实问过我是否应该忽略这个问题并继续前进。你的代码是在我已经尝试过 DHN 的解决方案并让它工作之后出现的——尽管我不是聪明的程序员——并且由于下一个书的指令是 delete Command.cs,我没有实施它。如果你的方法可行,我会尝试(并会投票),但我有我的解决方案。
【解决方案3】:

Action, Func 是 C# 设计实现闭包的方式。动作意味着你有参数对象的闭包并返回 System.Void 类型。 Func 是用参数对象实现闭包并返回 System.Bool 类型的方式。

有关 C# 中闭包的更多详细信息,请参阅The beauty of closure by Jon Skeet

【讨论】:

  • Action 并不意味着你有一个闭包,这意味着你有一个代表。该委托可以通过闭包创建,但也可以通过普通方法创建。
  • 是的。我只是提到Action是闭包的实现方式。
  • 它如何回答甚至与提出的问题相关联?
猜你喜欢
  • 1970-01-01
  • 2011-01-12
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
相关资源
最近更新 更多