Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

ICommand Interface in WPF

4.91/5 (49 votes)
8 Nov 2015CPOL11 min read 114.1K   3.2K  
ICommand interface and its use in generic implementation of Command
In this article, we will learn about ICommand interface and its use in generic implementation of Command while working with MVVM Pattern in WPF/Silverlight applications.

Introduction

In this article, we will learn about ICommand interface and its use in generic implementation of Command while working with MVVM (Model View ViewModel) Pattern in WPF/Silverlight applications. First, we will understand about Command and then look into members of ICommand interface. We will create a demo application in WPF to learn the use of ICommand. In the demo application, we will use MVVM Pattern also.

Note: For this article, as a prerequisite, we must have basic understanding of WPF and MVVM pattern. If you are new to MVVM Pattern, please have a look at Wiki and MSDN Page.

Outline

What is Command

In WPF context, Command is any class which implement ICommand interface. There is minute difference between Commands and Events. Events are defined and associated with UI Controls. But Commands are more abstract and focused on what to be done. One Command can be associated with multiple UI Controls/Options. For example, a Save Command we can be executed on Save Button Click, or by pressing Ctrl+S or by choosing Save option from Menu bar. To have interactions in application, we use either events or commands.

In WPF applications, we have two options to provide interactions in UI:

  • The first option is using events and write code in code-behind file which we want to execute on a particular event, if we are not following MVVM pattern. There are many inbuilt RoutedEvents available in WPF to use for this case.
  • The second option is write code block which we want to execute in ViewModel and invoke that code using Command, if we are following MVVM pattern. If we are using MVVM Pattern, then generally we should not write code in code-behind files. So we cannot use RoutedEvents because RoutedEvents are not accessible in ViewModels. That is why we have to use Commands to execute desired code block written in ViewModel. Thus Commands provide glue between View and ViewModel for interactivity.

ICommand Interface

ICommand is an interface which has three members as shown in the below table:

Member Of ICommand Description
bool CanExecute(object parameter)

CanExecute method takes an object as an argument and returns bool. If it returns true, associated command can be executed. If it returns false, associated command cannot be executed. Often, we pass a delegate to this method as an object which returns a bool. For that, we can use inbuilt delegate like Action, Predicate or Func.

event EventHandler CanExecuteChanged

This is used to notify the UI controls associated with Command if Command can be executed. Based on notification of this event, UI controls change its status as enabled or disabled. Basically, while "CanExecute" method executes and if there is a change in method's output (true/false), then this event is fired.

void Execute(object parameter)

This is the method which does actual work which is intended for the Command. This method executes only if CanExecute method returns true. It takes an object as an argument and we generally pass a delegate into this method. The delegate holds a method reference which is supposed to execute when Command is fired.

Why ICommand Interface

ICommand is core interface in WPF for Commands. It is heavily used in MVVM and Prism based application. But use of ICommand interface is not just limited to MVVM. There are many inbulit Commands which already implements this interface provided by WPF/Silverlight/Prism framework. The base class RoutedCommand implements ICommand interface. And WPF provides MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands, and EditingCommands which uses RoutedCommand class. For more information, please have a look at the MSDN Page.

To make it easy to understand, let us create a demo application.

Overview of Demo Application

The demo application is doing very basic calculation, just to show ICommand interface implementation. Demo application is having two textboxes to accept input value, one label to show output and four buttons to perform calculations. Four buttons are used to perform add, subtraction, multiply and divide operation. After entering values in textboxes, then on a button click, the associated command will get fired and it shows result in the label. How we will achieve the above functionality, we will see in further steps. Please download the code sample attached as it will be helpful to understand and follow up explanations given further.

The final screenshot of the demo application is as shown below:

Final Screen Shot of Demo App

Creating UI for Demo App

Now fire up Visual Studio and to create demo application, please follow the steps given below:

Step 1

Create a WPF application named as SimpleCommandDemoApp. Make project structure by adding folders and files same as shown below. In further steps, we will write code in those files.

Application Solution Image

Step 2

First, we will create a layout demo UI. To do that, we will create the grid with four rows and four columns. Controls will be placed in this grid by specifying rows and columns position. Write the same code as shown below in CalculatorView.xaml file.

XML
<Grid DataContext="{Binding Source={StaticResource calculatorVM}}"
Background="#FFCCCC">
    <Grid.RowDefinitions>
        <RowDefinition Height="80"></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition Height="80"></RowDefinition>
        <RowDefinition Height="44"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>

    <Label Grid.Row="0" Grid.Column="0"
    Grid.ColumnSpan="4" FontSize="25" VerticalAlignment="Top"
    HorizontalAlignment="Center" Foreground="Blue" Content="ICommand Demo"/>
    <Label Grid.Row="0" Grid.Column="0"
    Grid.ColumnSpan="2" Margin="10,0,0,0" VerticalAlignment="Bottom"
    FontSize="20"  Content="First Input"/>
    <Label Grid.Row="0" Grid.Column="2" Grid.ColumnSpan="2"
    Margin="10,0,0,0" VerticalAlignment="Bottom"
    FontSize="20"  Content="Second Input"/>

    <TextBox Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
    Margin="10,0,0,0" FontSize="20" HorizontalAlignment="Left"
    Height="30"  Width="150"
    TextAlignment="Center" Text="{Binding FirstValue, Mode=TwoWay}"/>
    <TextBox Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2"
    Margin="10,0,0,0" FontSize="20" HorizontalAlignment="Left"
    Height="30" Width="150" TextAlignment="Center"
    Text="{Binding SecondValue, Mode=TwoWay}"/>

    <Rectangle Grid.Row="2" Grid.Column="0"
    Grid.ColumnSpan="4" Fill="LightBlue"></Rectangle>
    <Button Grid.Row="2" Grid.Column="0" Content="+"
    Margin="10,0,0,0" HorizontalAlignment="Left" Height="50"
    Width="50" FontSize="30" Command="{Binding AddCommand}"></Button>
    <Button Grid.Row="2" Grid.Column="1" Content="-"
    Margin="10,0,0,0" HorizontalAlignment="Left" Height="50"
    Width="50" FontSize="30" Command="{Binding SubstractCommand}"></Button>
    <Button Grid.Row="2" Grid.Column="2" Content="*"
    Margin="10,0,0,0" HorizontalAlignment="Left" Height="50"
    Width="50" FontSize="30" Command="{Binding MultiplyCommand}"></Button>
    <Button Grid.Row="2" Grid.Column="3" Content="%"
    Margin="10,0,0,0" HorizontalAlignment="Left" Height="50"
    Width="50" FontSize="30" Command="{Binding DivideCommand}"></Button>

    <Label Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2"
    FontSize="25" Margin="10,0,0,0" HorizontalAlignment="Left"
    Height="50"  Content="Result : "/>
    <TextBlock Grid.Row="3" Grid.Column="2" Grid.ColumnSpan="2"
    FontSize="20" Margin="10,0,0,0" Background="BlanchedAlmond"
    TextAlignment="Center"  HorizontalAlignment="Left" Height="36"
    Width="150" Text="{Binding Output}"/>
</Grid>

Now go to MainWindow.xaml file, add namespace of CalculatorView.xaml file so that we can access CalculatorView.xaml in MainWindow.

XML
xmlns:views="clr-namespace:SimpleCommandDemoApp.Views"

Create a tag for CalculatorView.xaml view inside parent grid of MainWindow.xaml.

XML
<Grid>
    <views:CalculatorView/>
</Grid>

Step 3

Now we need to attach properties of two textboxes and label in CalculatorView.xaml to its ViewModel called CalculatorViewModel.

As we can see in XAML, we have bounded UI propertites with ViewModel properties. CalculatorViewModel's property “FirstValue” is bounded with "Text" property of first textbox, CalculatorViewModel's property “SecondValue” is bounded with "Text" property of second textbox. And CalculatorViewModel's property “Output” is bounded with “Content” property of label.

To do Binding with CalculatorViewModel, create three private fields called firstValue, secondValue and output and three public properties with the same name what we have given for binding of text property of the textboxes and label. We must provide the same names to three properties as we have used while binding for Text property of textboxes in UI.

Property “FirstValue” is written as shown below, in a similar way, we have to create two more properties named as “SecondValue” and “Output” in CalculatorViewModel.

C#
public double FirstValue
{
    get
    {
        return firstValue;
    }
    set
    {
        firstValue = value;
    }
}

How to Use ICommand Interface

To bind Commands with UI Controls, we need to create a command class which must implement ICommand interface.

First, we would be creating a command class for each button's functionality. Later, we will see how we can reuse a single generic command class to handle those functionality. As of now, we will first create individual command for "Add" functionality.

Step 4

We have already created a “Plus” button on UI page. As we are following MVVM pattern, in this case to handle such kind of functionality, we need to implement ICommand interface. Let us do that by writing the below code in PlusCommand Class.

C#
public class PlusCommand : ICommand
{
    // Creating private field of CalculatorViewModel
    // and passing calculatorViewModel into the constructor
    private CalculatorViewModel calculatorViewModel;
    public PlusCommand(CalculatorViewModel vm)
    {
        calculatorViewModel = vm;
    }
    public bool CanExecute(object parameter)
    {
        return true;
    }
    public void Execute(object parameter)
    {
        calculatorViewModel.Add();
    }

    public event EventHandler CanExecuteChanged;
}

Step 5

Now create a private field of PlusCommand class in CalculatorViewModel and create an instance of PlusCommand class inside the constructor of CalculatorViewModel.

C#
private PlusCommand plusCommand;
public CalculatorViewModel()
{
    plusCommand = new PlusCommand(this);
}

Step 6

Register namespace of CalculatorViewModel to CalculatorView.xaml file. For that, the below line of code needs to be added in namespace area.

XML
xmlns:vm="clr-namespace:SimpleCommandDemoApp.ViewModels"

After namespaces, add UserControl.Resources tag to register CalculatorViewModel by specifying the key "calculatorVM". Same key we have used while providing DataContext Binding to the grid.

XML
<UserControl.Resources>
    <vm:CalculatorViewModel x:Key="calculatorVM" />
</UserControl.Resources>

Step 7

Implement Add method in CalculatorViewModel.

C#
public void Add()
{
   Output = firstValue + secondValue;
}

Step 8

Create a command named as “AddCommand” name in CalculatorViewModel. Command’s name must be same as we have given for button's Command property binding in CalculatorView.xaml file. Code for AddCommand is shown below:

C#
internal ICommand AddCommand
{
   get
   {
       return plusCommand;
       // return new RelayCommand(Add);
   }
}

Step 9

Now run the application, click on “Plus” button, CalculatorViewModel constructor will be called because we have given reference of CalculatorViewModel in CalculatorView.xaml file as DataContext. From the constructor of CalculatorViewModel, we are creating the instance of PlusCommand. While creating instance of PlusCommand, we are passing CalculatorViewModel ViewModel itself using “this” keyword.

While execution of AddCommand, first CanExecute method will be called which will return "true" as we have hardcoded it for simplicity. Then Execute method will be called and it will invoke Add method of CalculatorViewModel.

Put the breakpoint to Add method and run the application, we will see values entered into textboxes are available in firstValue, secondValue variables. And calculated result will be assigned to Output property. But result is not visible on the screen in the content of label. If we want to see the result on UI, we have to implement INotifyPropertyChanged Interface so that Change in "Output" property of ViewModel can be notified to UI.

Need of INotifyPropertyChanged

The purpose of INotifyPropertyChanged is to notify if any changes happen to a property to all of its references (UI Controls/ViewModel). Since by default, UI properties (i.e., Text property of Textbox) mostly have INotifyPropertyChanged implemented. Now we need to implement this interface for ViewModels too, so that if any change occurs in ViewModel side, it can be notified/reflected to UI.

Step 10

As we have seen in the above step, “Output” is the name of CalculatorViewModel’s property, which we have bound to the Content property of label. When call comes to Add method, we assign calculated value to “Output” property. Since “Output” is a public property and bound to UI, this way change will be reflected to label. Now with the help of INotifyPropertyChanged, label’s Content will be updated.

So let us implement INotifyPropertyChanged interface in ViewModelBase class. The code is as shown below:

C#
public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                 }
            }
    }

Step 11

Inherit CalculateViewModel from ViewModelBase, add one line of code inside the set block of all three public properties as shown below:

C#
OnPropertyChanged("FirstValue");

OnPropertyChanged is a method which takes property name as argument. We have implemented this method in ViewModelBase class. Whenever any change will occur in properties either from UI or ViewModel, OnPropertyChanged method will be called. Since we have written Mode=TwoWay in XAML code for first textbox and second textbox, whenever there will be any change either at UI side or ViewModel side, another party (UI or ViewModel) will be notified.

Now run the application, we would be able to perform Add operation and result will be visible in Output label. We need to follow the same steps for the rest of the button click commands to achieve three more calculations.

Problem with Individual Commands

As of now, we need to create separate command classes for each operation. As we have done, for PlusCommand class, it has the following drawbacks:

First: PlusCommand class is tightly coupled with CalculatorViewModel because PlusCommand class is having the reference of CalculatorViewModel.

Second: From Execute method, we are calling Add method of CalculatorViewModel. In future, if we change the name of Add method, then we have to modify (Execute method of) PlusCommand class also.

Third: As we cannot reuse PlusCommand class for other operations, so for every event, we need to write many different individual command classes for each operation. In our case, on “Plus” button click, we are calling Add method. But for “Minus” button click, we need to call Subtract method, which we cannot do by using PlusCommand Class. That is why we have created four Command classes to handle each click event named as PlusCommand, MinusCommand, MultiplyCommand and DivideCommand, which is not a good approach.

That’s why we create a generic command class to handle all kind of operations. For that, we can use inbuilt delegates.

Generic Implementation of Command

There are many inbuilt delegates like Action, Func and Predicate, etc. with .NET Framework. In our demo application, we will use Action delegate. For more information about Action, have a look here. Then we will see how to makes our work easy by increasing reusability.

Step 12

In the above steps, we have created four command classes to handle four button click event. Now by using Action delegate, we will remove all of four command classes, by creating one generic command class called RelayCommand. We can give any name instead of RelayCommand. As a good practice, we should give some meaningful name. Write the below code in RelayCommand class:

Code of RelayCommand Class

Now we need to change one line of code. Comment the first line and uncomment the second line of get block of AddCommand property as shown below:

C#
public ICommand AddCommand
    {
        get
        {
            //return plusCommand;
            return new RelayCommand(Add);
        }
    }

Before returning from this get block, the constructor of RelayCommand will be called which takes a method as an Action delegate. Here, we are passing name of Add method to Action delegate parameter.

Put the breakpoint on constructor of RelayCommand and run the application. We will be able to see the name of Add method in workToDo local variable as shown below:

Code Execution of RelayCommand Class

Now all four operations can be handled just by using RelayCommand class. Now we can remove all of four command classes as we have created in folder "Commands\Specific".

Conclusion

In this article, we had a walkthrough to learn ICommand Interface and its use. We understood how to use ICommand interface to create generic Command class as a standard practice of MVVM pattern. Thanks for reading. Your comments and suggestions for improvement are most welcome.

History

  • 8th November, 2015: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)