WPF ICommand In MVVM

Introduction

Commands provide a mechanism for the view to update the model in the MVVM architecture. Commands provide a way to search the element tree for a command handler. The ICommand interface is defined inside the System.Windows.Input namespace. It has two methods and an event.

  1. bool CanExecute(object parameter);  
  2. void Execute(object parameter);  
  3. event EventHandler CanExecuteChanged;   

The Execute method is only invoked when CanExecute returns true. In case the CanExecute method returns false then the binding control is disabled automatically.

In order to know the CanExecute value, listen to the CanExecuteChanged event, that may vary based on the parameter passed.

Using Code

Use of ICommand

The ICommand interface is generally used in the MVVM architecture. Here in the Button control the Command property is bound to the "UpdateCommand". Since UpdateCommand is nothing but an ICommand instance, while loading the window it will check the CanExecute return value and if it returns true then it will enable the button control and the Execute method is ready to be used otherwise the button control is disabled.

  1. <Button x:Name="btnUpdate" Width="100" Height="20" HorizontalAlignment="Center" Grid.Row="1" Content="Update" Command="{Binding Path=UpdateCommand}"/>  

Passing a parameter to the CanExecute and Execute methods

A parameter can be passed through the "CommandParameter" property. Once the button is clicked the selected address value is passed to the ICommand.Execute method.

The CommandParameter is sent to both CanExecute and Execute events.

  1. <Button x:Name="btnUpdate" Width="100" Height="20" HorizontalAlignment="Center" Grid.Row="1" Content="Update" Command="{Binding Path=UpdateCommand}" CommandParameter="{Binding ElementName=lstPerson, Path=SelectedItem.Address}">  
  2. </Button>  

Tasks of CanExecuteChanged

CanExecuteChanged notifies any command sources (like a Button or CheckBox) that are bound to that ICommand that the value returned by CanExecute has changed. Command sources care about this because they generally need to update their status accordingly (eg. a Button will disable itself if CanExecute() returns false).

Listen CanExecuteChanged

The CommandManager.RequerySuggested event is raised whenever the CommandManager thinks that something has changed that will affect the ability of commands to execute. This might be a change of focus, for example. This event happens to fire a lot.

  1. public event EventHandler CanExecuteChanged  
  2. {  
  3.     add { CommandManager.RequerySuggested += value; }  
  4.     remove { CommandManager.RequerySuggested -= value; }  
  5. }   

ICommand in MVVM

UI

WPF ICommand In MVVM

Model 

Create a folder named Model and a class named Person. Implement INotifyPropertyChanged and override the PropertyChanged event. Define two properties, Name and Address.

  1. public class Person : INotifyPropertyChanged  
  2. {  
  3.     private string name;  
  4.     private string address;  
  5.    
  6.     public event PropertyChangedEventHandler PropertyChanged;  
  7.     public void OnPropertyChanged(string propertyName)  
  8.     {  
  9.         if (PropertyChanged != null)  
  10.         {  
  11.              PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));  
  12.         }  
  13.     }  
  14.    
  15.     public string Name  
  16.     {  
  17.         get  
  18.        {  
  19.            return name;  
  20.        }  
  21.        set  
  22.        {  
  23.            name = value;  
  24.            OnPropertyChanged("Name");  
  25.        }  
  26.     }  
  27.   
  28.     public string Address  
  29.     {  
  30.         get  
  31.         {  
  32.             return address;  
  33.         }  
  34.         set  
  35.         {  
  36.             address = value;  
  37.             OnPropertyChanged("Address");  
  38.         }  
  39.     }  
  40. }   

ViewModel

Create a folder named ViewModel and a class named PersonViewModel. Initialize a List object of type person. Expose this object through the Persons property. Also expose an ICommand instance in this class.

Define a class Updater and implement ICommand interface.

  1. public class PersonViewModel  
  2. {  
  3.     private IList<Person> _personList;  
  4.     public PersonViewModel()  
  5.     {  
  6.         _personList = new List<Person>()  
  7.         {  
  8.             new Person(){Name="Prabhat", Address="Bangalore"},  
  9.             new Person(){Name="John",Address="Delhi"}  
  10.         };  
  11.     }  
  12.     public IList<Person> Persons  
  13.     {  
  14.         get { return _personList; }  
  15.         set { _personList = value; }  
  16.     }  
  17.     private ICommand mUpdater;  
  18.     public ICommand UpdateCommand  
  19.     {  
  20.         get  
  21.         {  
  22.             if (mUpdater == null)  
  23.                 mUpdater = new Updater();  
  24.             return mUpdater;  
  25.         }  
  26.         set  
  27.         {  
  28.             mUpdater = value;  
  29.         }  
  30.     }  
  31. }  
  32. class Updater : ICommand  
  33. {  
  34.     #region ICommand Members  
  35.   
  36.     public bool CanExecute(object parameter)  
  37.     {  
  38.         return true;  
  39.     }   
  40.     public event EventHandler CanExecuteChanged  
  41.     {  
  42.         add { CommandManager.RequerySuggested += value; }  
  43.         remove { CommandManager.RequerySuggested -= value; }  
  44.     }   
  45.   
  46.     public void Execute(object parameter)  
  47.     {  
  48.          //Your Code  
  49.     }  
  50.     #endregion  
  51. }  

View

Create a view folder and a Person.xaml class. Bind the command to the button control. Once the button is clicked, the command parameter is passed to the Execute method. You can also bind a command to any control that supports the command property. The TextBox is bound with listView selectedItem.

  1. <Grid>  
  2.        <Grid.RowDefinitions>  
  3.            <RowDefinition Height="auto"/>  
  4.            <RowDefinition Height="auto"/>  
  5.            <RowDefinition Height="*"/>  
  6.        </Grid.RowDefinitions>  
  7.        <Grid>  
  8.            <Grid.ColumnDefinitions>  
  9.                 <ColumnDefinition Width="100"></ColumnDefinition>  
  10.                 <ColumnDefinition Width="*"></ColumnDefinition>  
  11.            </Grid.ColumnDefinitions>  
  12.            <Grid.RowDefinitions>  
  13.                 <RowDefinition Height="auto"></RowDefinition>  
  14.                 <RowDefinition Height="auto"></RowDefinition>  
  15.            </Grid.RowDefinitions>  
  16.            <Label x:Name="lblName" Content="Name" Grid.Row="0" Grid.Column="0" VerticalAlignment="Top"></Label>  
  17.            <TextBox x:Name="txtName" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top" Text="{Binding ElementName=lstPerson, Path=SelectedItem.Name}">  
  18.            </TextBox>  
  19.            <Label x:Name="lblAddress" Content="Address" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top"></Label>  
  20.            <TextBox x:Name="txtAddress" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" Text="{Binding ElementName=lstPerson   
  21.            Path=SelectedItem.Address}"></TextBox>  
  22.        </Grid>  
  23.        <Button x:Name="btnUpdate" Width="100" Height="20" HorizontalAlignment="Center" Grid.Row="1" Content="Update"  
  24.                Command="{Binding Path=UpdateCommand}" CommandParameter="{Binding ElementName=lstPerson, Path=SelectedItem.Address}"></Button>  
  25.        <ListView x:Name="lstPerson" Grid.Row="2" ItemsSource="{Binding Persons}">  
  26.   
  27.            <ListView.View>  
  28.                 <GridView>  
  29.                     <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />  
  30.   
  31.                     <GridViewColumn Header="Address" Width="200" DisplayMemberBinding="{Binding Address}"/>  
  32.                 </GridView>  
  33.            </ListView.View>  
  34.        </ListView>  
  35.     </Grid>   

App.xaml.cs

Override the OnStartup method of the Application class. Initialize a view and viewModel class and wrap a viewmodel to the view by the DataContext property.

  1. protected override void OnStartup(StartupEventArgs e)  
  2. {  
  3.     base.OnStartup(e);  
  4.     View.Person person = new View.Person();  
  5.     PersonViewModel personViewModel = new PersonViewModel();  
  6.     person.DataContext = personViewModel;  
  7.     person.Show();  
  8. }  

Summary

  1. What is ICommand in WPF.
  2. How ICommand used in MVVM architecture.
  3. MVVM architecture flow.
  4. How to pass parameter in CanExecute and Execute method.
  5. How to listen to CanExecuteChanged event.

Point Of Interest

Instead of events, commands have been used in the MVVM architecture. We cannot pass a parameter to the event but we can pass a parameter through a command.