Click here to Skip to main content
14,659,588 members
Articles » Platforms, Frameworks & Libraries » Windows Presentation Foundation » Applications
Article
Posted 8 Nov 2015

Stats

74K views
2.8K downloads
37 bookmarked

ICommand Interface in WPF

Rate this:
4.90 (46 votes)
Please Sign up or sign in to vote.
4.90 (46 votes)
8 Nov 2015CPOL
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 use of ICommand. In demo application we will use MVVM Pattern also.

Note: For this article, as 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.

Outlines

  • What is Command
  • ICommand Interface
  • Why ICommand Interface
  • Overview of Demo Application
  • Creating UI for Demo App
  • How to use ICommand Interface
  • Need of INotifyPropertyChanged
  • Problem with Individual Commands
  • Generic Implementation of Command

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:

  • 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.

  • 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 provides glue between View and ViewModel for interactivity.

ICommand Interface

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

Member Of ICommand Description
bool CanExecute(object parameter)

CanExecute method takes an object as an argument and return bool. If it returns true, associated command can be executed. If it returns false, associated command can not 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 execute 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 implememts ICommand interface. And WPF provides MediaCommands, ApplicationCommands, NavigationCommands, ComponentCommands, and EditingCommands which uses RoutedCommand class. For more information, please have a look 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 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.

Final screen shot of demo application.

Final Screen Shot of Demo App
 

Creating UI for Demo App

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

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 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.

<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.

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

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

<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 textboxs 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 similar way we have to create two more property named as “SecondValue” and “Output” in CalculatorViewModel.

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. Already we have created “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 below code in PlusCommand Class.

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.

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

Step 6. Register namespace of CalculatorViewModel to CalculatorView.xaml file. For that below line of code need to add in namespace area.

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.

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

Step 7. Implement Add method in CalculatorViewModel.

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.

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 labe. 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 happenes 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 above step, “Output” is 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. Code as shown below.

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.

OnPropertyChanged("FirstValue");

OnPropertyChanged is a method which takes property name as argument. This method we have implemented 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 so whenever that 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. Same steps we need to follow for rest of button click commands to achieve more three calculations.

Problem with Individual Commands

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

First: PlusCommand class 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 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 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 first line and uncomment second line of get block of AddCommand property as shown below.

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

Before returning from this get block, 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 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.

License

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

Share

About the Author

Snesh Prajapati
Software Developer
India India
I am a Software Developer working on Microsoft technologies. My interest is exploring and sharing the awesomeness of emerging technologies.

Comments and Discussions

 
PraiseI cannot thank you enough!! Pin
Member 1435422513-May-20 3:27
MemberMember 1435422513-May-20 3:27 
QuestionMerci beacoup Pin
said0113-Apr-20 10:24
Membersaid0113-Apr-20 10:24 
Praisevery useful Pin
Member 1367122725-Mar-20 1:17
MemberMember 1367122725-Mar-20 1:17 
QuestionWonderfully explained. Pin
Member 1466647024-Nov-19 4:33
MemberMember 1466647024-Nov-19 4:33 
PraiseComprehensive Article on ICommand Pin
Member 1345943229-Jul-19 20:27
MemberMember 1345943229-Jul-19 20:27 
QuestionRelayCommand not in the framework. Pin
Member 1450762520-Jun-19 22:37
MemberMember 1450762520-Jun-19 22:37 
QuestionMost beautiful and useful article in code project I ever seen. Pin
Member 1412942127-Jan-19 3:25
MemberMember 1412942127-Jan-19 3:25 
Questioninternal Command AddCommand must be public Pin
Member 128874599-Jan-19 3:10
MemberMember 128874599-Jan-19 3:10 
GeneralMy vote of 5 Pin
sbarnes13-Oct-18 20:08
Membersbarnes13-Oct-18 20:08 
QuestionOne little problem ... Pin
Francesco La Gamba30-Jun-18 5:57
MemberFrancesco La Gamba30-Jun-18 5:57 
GeneralNice Pin
Kishore Kishh10-May-18 8:59
MemberKishore Kishh10-May-18 8:59 
QuestionGood! Pin
Member 84219082-Mar-18 3:35
MemberMember 84219082-Mar-18 3:35 
SuggestionUse of delegates Pin
niksofteng16-Feb-18 5:16
Memberniksofteng16-Feb-18 5:16 
QuestionOne of the Nice Article - I ever Read Pin
Member 1235327626-Jan-18 22:39
MemberMember 1235327626-Jan-18 22:39 
QuestionYou're a natural! Pin
Müdürüm15-Nov-17 6:51
MemberMüdürüm15-Nov-17 6:51 
PraiseDetailed explanation Pin
Member 116515089-Oct-17 4:42
MemberMember 116515089-Oct-17 4:42 
AnswerRe: Detailed explanation Pin
Snesh Prajapati9-Oct-17 7:47
professionalSnesh Prajapati9-Oct-17 7:47 
QuestionVery nice and useful article! One question - How to do action specific validation in CanExecute()? Pin
Member 115352108-May-17 20:05
MemberMember 115352108-May-17 20:05 
QuestionAwesome article.! Pin
Park JunYoung15-Mar-17 21:45
MemberPark JunYoung15-Mar-17 21:45 
QuestionComplete understanding of mvvm and Icommand Pin
Member 110426996-Feb-17 20:45
MemberMember 110426996-Feb-17 20:45 
GeneralWonderful article. Pin
sumitk.cadc20-Nov-16 17:43
Membersumitk.cadc20-Nov-16 17:43 
AnswerRe: Wonderful article. Pin
Snesh Prajapati21-Nov-16 5:04
professionalSnesh Prajapati21-Nov-16 5:04 
PraiseWell done! Pin
Member 1268465713-Aug-16 13:51
MemberMember 1268465713-Aug-16 13:51 
AnswerRe: Well done! Pin
Snesh Prajapati13-Aug-16 14:56
professionalSnesh Prajapati13-Aug-16 14:56 
PraiseThank you so much Pin
Member 124886162-Aug-16 4:00
MemberMember 124886162-Aug-16 4:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.