使用Action<>的命令和Func<>

时间:2013-04-24 08:14:34

标签: c# wpf mvvm icommand relaycommand

我正在MVVM Survival Guide for Enterprise Architectures in Silverlight and WPF工作,并且在命令部分遇到了麻烦。具体而言,它基于Action< object>创建命令。和Func< object,bool>。在我应该“构建并运行应用程序”的时候,我反而遇到了编译错误。

命令:

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<object>, System.Func<object, bool>)的最佳重载匹配有一些无效的参数'。

当我尝试编译时,我得到上述错误,加上两条消息:

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

为了保存我的额头/最近的墙,有人可以告诉我我做的不对,所以我可以解决它,或者给定的(书)代码导致我出错,所以我可以继续前进。 / p>

3 个答案:

答案 0 :(得分:2)

那是因为

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

不是Func<object, bool>类型,而是Func<bool>类型。它应该看起来像

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

您可以使用Predicate<object>代替,至少对我来说,更清楚,签名应该如何。

答案 1 :(得分: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. - MVVM Silverlight和WPF企业架构生存指南,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上(它位于“方法调用内容:”之后):

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),这会带来更多变化和更多必需品,以便在每次顺序更改时更改代码。

只需运行代码并尝试合并您的更改即可查看它将调用的内容

答案 2 :(得分:0)

动作,Func是C#设计实现闭包的方式。 Action表示您使用参数对象进行闭包并返回 System.Void 类型。 Func是使用参数对象实现闭包并返回 System.Bool 类型的方法。

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