Icommand Mvvm Implementation

ICommand MVVM implementation

This is almost identical to how Karl Shifflet demonstrated a RelayCommand, where Execute fires a predetermined Action<T>. A top-notch solution, if you ask me.

public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;

public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}

public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}

public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}

public void Execute(object parameter)
{
_execute(parameter);
}
}

This could then be used as...

public class MyViewModel
{
private ICommand _doSomething;
public ICommand DoSomethingCommand
{
get
{
if (_doSomething == null)
{
_doSomething = new RelayCommand(
p => this.CanDoSomething,
p => this.DoSomeImportantMethod());
}
return _doSomething;
}
}
}

Read more:

Josh Smith (introducer of RelayCommand): Patterns - WPF Apps With The MVVM Design Pattern

What is the reason for ICommand in Mvvm?


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

Understanding ICommand implementation without MVVM

Your CanExecuteChanged shouldn't be raised by Execute, it should be raised when CanExecute will start returning a different value. When that is depends on your command class. In the simplest form, you could add a property:

public class MyCommand : ICommand
{
bool canExecute;

public void Execute(object parameter)
{
Console.WriteLine("Execute called!");
}

public bool CanExecute(object parameter)
{
Console.WriteLine("CanExecute called!");
return CanExecuteResult;
}

public event EventHandler CanExecuteChanged;

public bool CanExecuteResult
{
get { return canExecute; }
set {
if (canExecute != value)
{
canExecute = value;
var canExecuteChanged = CanExecuteChanged;
if (canExecuteChanged != null)
canExecuteChanged.Invoke(this, EventArgs.Empty);
}
}
}
}

ICommand implementations in a separate classes, using only MVVM Light?

The way I do is that I have "sub-viewmodels". For example, in the case of the MainViewModel, let's imagine that you have a PrintCommand and a CancelPrintCommand. You can have a new class called PrinterViewModel, and expose an instance of this class in the MainViewModel. Have the PrintCommand and the CancelPrintCommand in this PrinterViewModel (this also allows modular unit testing, which is neat).

Then in XAML:

Command="{Binding Main.Printer.PrintCommand}"

Alternatively, you could do

new RelayCommand(() => Printer.DoSomething())

Does that make sense?

Cheers
Laurent

When implementing ICommand in MVVM I'm missing something

The buttons become activated or deactivated since they're bound to an ICommand. ICommand includes a CanExecute property, which determines whether the button is active or not.

I can't see where these things are actually happening.

The command uses delegates:

 _getProductCommand = new RelayCommand(
param => GetProduct(),
param => ProductId > 0
);

The second delegate causes the command to be activated (CanExecute becomes true) when ProductId > 0 (the delegate returns true).

When you click the button, the command's Execute method fires, and performs the actions.

As for the window starting up in the first place, look at the section titled "Starting the Sample" - there's code in app.xaml.cs which is used to display the Window at first.

Implementing MVVM in WPF without using System.Windows.Input.ICommand

You should be able to define a single WPF custom routed command in your wpf layer and a single command handler class. All your WPF classes can bind to this one command with appropriate parameters.

The handler class can then translate the command to your own custom command interface that you define yourself in your ViewModel layer and is independent of WPF.

The simplest example would be a wrapper to a void delegate with an Execute method.

All you different GUI layers simply need to translate from their native command types to your custom command types in one location.

Implementing and using the ICommand interface, MVVM

You can add CommandParameter="" to pass a parameter. Usually you'll pass in the binding, or an id that's part of the binding, so the command knows what record to work with.



Related Topics



Leave a reply



Submit