2

I'm trying to learn about the ICommand interface, and I'm getting a bit confused. What I want, is to have commands which don't require the object parameter because it's never used.

class MainWindowViewModel
{
    private int ZoomLevel { get; set; }

    public bool CanExecute { get; set; }

    public ICommand ToggleExecuteCommand { get; set; }

    public ICommand IncrementZoomCommand { get; set; }

    public MainWindowViewModel()
    {
        IncrementZoomCommand = new RelayCommand(IncrementZoom, param => CanExecute);
        ToggleExecuteCommand = new RelayCommand(ChangeCanExecute);
    }

    public void IncrementZoom(object obj)
    {
        ZoomLevel++;
    }

    public void ChangeCanExecute(object obj)
    {
        CanExecute = !CanExecute;
    }
}

Here is my RelayCommand class

public class RelayCommand : ICommand
{
    private Action<object> execute;

    private Predicate<object> canExecute;

    private event EventHandler CanExecuteChangedInternal;

    public RelayCommand(Action<object> execute)
        : this(execute, DefaultCanExecute)
    {
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        if (canExecute == null)
        {
            throw new ArgumentNullException("canExecute");
        }

        this.execute = execute;
        this.canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
            this.CanExecuteChangedInternal += value;
        }

        remove
        {
            CommandManager.RequerySuggested -= value;
            this.CanExecuteChangedInternal -= value;
        }
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute != null && this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute(parameter);
    }

    public void OnCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChangedInternal;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }

    public void Destroy()
    {
        this.canExecute = _ => false;
        this.execute = _ => { return; };
    }

    private static bool DefaultCanExecute(object parameter)
    {
        return true;
    }
}

Due to the fact that the RelayCommand class has been implemented using Action<Object> (seems universal across SO) I have to pass an object into my IncrementZoom method. It seems strange to me that the IncrementZoom method has to have an object passed in which is never used. Would I need to create another class ParameterlessRelayCommand which has all the object signatures removed from the constructors, methods, properties etc...

Ralt
  • 2,084
  • 1
  • 26
  • 38
  • 4
    UIElements with a bindable Command property also have a bindable CommandParameter property, the value of which is passed as object argument to Execute and CanExecute. It can contain a simple string, or a complex object, and of course also be null (which it is by default, i.e. if you don't set the CommandParameter). – Clemens Jul 07 '17 at 07:58
  • @Clemens Happy to accept this as an answer if you want to post. I didn't know if this would look like unclean code - and because I didn't know why it was happening, I wouldn't have been able to justify it. – Ralt Jul 07 '17 at 08:03

0 Answers0