简体   繁体   中英

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?

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

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

How would you for example call a public method when a Button in the view is clicked?

The answer is that you bind the Command property of the Button to an ICommand property of the view model that calls the method for you. That's the main reason why any actions that view model defines are exposed using commands.

A command is nothing but an object that implements the System.Windows.Input.ICommand interface and encapsulates the code for the action to be performed.

Please refer to the following links for more information about the concept.

https://blog.magnusmontin.net/2013/06/30/handling-events-in-an-mvvm-wpf-application/ https://msdn.microsoft.com/en-us/magazine/dn237302.aspx

In MVVM you try to avoid "code behind" (this is code in the MyView.cs file) to avoid a tight coupling of View, ViewModel and Model.

In MFC you just registered an event handler (which is still possible in WPF), but in MVVM there is the possibility of just binding a ICommand which will be executed instead of triggering the event.

Short: ex. Buttons Buttons works by creating event (Click="XEvent") that consist of method and then we tell application what to do next ie call other methods obviously that works with Code behind. (Event => method is generated at MainWindow.xaml.cs .)

In MVVM we avoid code behind pattern. to achieve that we need to set the DataContext to other class (will act as middleware) say MainWindowViewModel.cs .

By implementing ICommand interface and implementing methods to handle the command we avoid code behind maintain MVVM pattern.

Well there can be alternative to ICommand interface like to bind method in ViewModel to command in XAML (Wont prefer though) here

<Button Command="{ViewModel AnyMethodName}"/>

PLUS ICommand interface will provide you CanExecute method which can be used to enable/Disable controllers simple delegate wont give u that functionality Hope this helps :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM