Question

I am working through MVVM Survival Guide for Enterprise Architectures in Silverlight and WPF and have hit a snag in the Command section. Specifically, it creates a command based on an Action<object> and Func<object, bool>. At a point where I'm supposed to 'build and run the application', I am instead getting compile errors.

The command stuff:

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);
  }
  ...
}

The method call stuff:

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);
}

I get wavy blue lines under the new Command(ShowCustomerDetails, IsCustomerSelected)) bit with a 'The best overloaded match for Northwind.Application.Command.Command(System.Action<object>, System.Func<object, bool>) has some invalid arguments'.

When I try to compile, I get the above error, plus two messages:

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

Now, I know a lot more about Actions and Funcs than I did yesterday, and can almost bypass the errrors by changing the command declaration to:

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

and doing similar throughout the code, but then I get an error saying I haven't implemented ICommand properly.

To save my forehead/the nearest wall, can somebody either tell me what I haven't done right so I can fix it, or that the given (book) code is leading me awry, so I can move on.

Was it helpful?

Solution

Well that's because

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

is not of type Func<object, bool> but of Func<bool>. It should look like

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

You could use Predicate<object> instead , which is, at least for me, more clear, how the signature should look like.

OTHER TIPS

It should be tip top after you substitute your Command class to the code below

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());     }
}

Checked this on the code from the mentioned book (p.205, Chapter 5)

  • Vice R., Shujaat Siddiqi M. - MVVM Survival Guide for Enterprise Architectures in Silverlight and WPF, PACKT Publishing, ISBN 978-1-84968-342-5, 2012

This is the error/typo in text of book

Really, in the accompanying code to this book which anyone can get from Download the support files for this book, the correct RelayCommand class is used instead of Command class in the text of the book, according to which I made changes above to Command class

BTW, it is absent in online errata to the book


Response to @DHN comment

Changing to IsCustomerSelected() method to IsCustomerSelected(object param) will bring

on ShowCustomerDetails in following snippet (it is after "The method call stuff:" in question):

private Command _showDetailsCommand;

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

the error:

Expected a method with 'void ShowCustomerDetails(object)' signature

since ShowCustomerDetails() is:

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

and if to change the latter ShowCustomerDetails(object param) this brings more changes and more necessities to change the code with each sequential change.

Just run the code and try incorporate your change to see what it would invoke

Action, Func is the way C# design for implementation of closure. Action means that you have closure with parameter object and return System.Void type. Func is the way to implement closure with parameter object and return System.Bool type.

For more detail about closure in C#, see The beauty of closure by Jon Skeet

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top