Search code examples
c#wpfmvvmicommand

What is the reason for ICommand in Mvvm?


In application using a mvvm-approach it's pretty common that the ViewModel provides one or more Command-properties. These properties often have the type ICommand or DelegateCommand or something like that.

I don't understand why we need such an approach in an mvvm application. Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method?

Why does ICommand exist?


Solution

  • Wouldn't it be enough to provide public methods and bind the action from the view directly to this public method? Why ICommand exists?

    1. you can't bind to a method in xaml. You need an object. Therefore you need to wrap the method to an object.

    2. it is a common pattern in UI, that some actions are not available all the time. In Login form the Login action become available only when you enter username. In MS Word, the Copy or Cut actions becomes available only when you select something, otherwise the buttons are disabled and keyboard shortcuts inactive

    3. it is a common pattern, that command can be invoked with different parameters.

    Plain eventhandlers does not meet those requirements, But ICommand servers exactly those purposes:

    public interface ICommand
    {
        void Execute(object parameter);
        bool CanExecute(object parameter);
        event EventHandler CanExecuteChanged;
    }
    
    1. It wraps method to an object
    2. It says whether to command is available or no, so the UI component (typically a button or menuitem) can reflect it
    3. Additionally, it notifies the UI components that the availability of the command has changed, so the UI can reflect it.

    Now, let's consider Copy&Paste scenario. Using ICommand the markup can look like this:

    <Button Content="Paste" Command="{Binding PasteCommand}" />
    <MenuItem Header="Paste" Command="{Binding PasteCommand}" />
    
    public ICommand PasteCommand {get;} = new DelegateCommand(Paste, () => Clipboard != null);
    

    How would it look like without ICommand? To make it easier, lets consider, that XAML would allow to bind to methods:

    <Button Content="Paste" Click="{Binding Paste}" IsEnabled="{Binding CanPaste}" />
    <MenuItem Header="Paste" Click="{Binding Paste}" IsEnabled="{Binding CanPaste}"/>
    
    public void Paste() {....}
    
    private bool _canPaste;
    public bool CanPaste
    {
        get { return _canPaste }
        set 
        { 
            if (_canPaste != value)
            {
                _canPaste = value;
                OnNotifyPropertyChanged(nameof(CanPaste);
            }
        }
    }
    

    as you can see, not only it is more verbose, but it's also violation of DRY principle. You need to specify both Paste and CanPaste binding every time you want to use the command. What if you started without CanPaste and later you wanted to add it. Then you would have to add the CanPaste binding every occurrence of the Paste call. I guarantee you, that you would forget it somewhere.

    Now, if you did this in WPF:

    <Button Content="Paste" Click="Call_ViewModel_Paste" />
    
    //in codebehind:
    void Call_ViewModel_Paste(oobject sender, RoutedEventArgs e)
    {
        ViewModel.Paste();
    }
    

    or eventually:

    <Button Content="Paste">
         <i:Interaction.Triggers>
             <i:EventTrigger EventName="Click">
                 <ei:CallMethodAction MethodName="Paste" TargetObject="{Binding}"/>
             </i:EventTrigger>
         </i:Interaction.Triggers>
    </Button>
    

    Both approaches are correct, they follow MVVM priciples and works without ICommand, but as you can see, neither is as elegant as ICommand