Reproduced:https://www.codeproject.com/Articles/1052346/ICommand-Interface-in-WPF
Author: Snesh Prajapati
---------------------------------------
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.
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.
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.
![](https://i-blog.csdnimg.cn/blog_migrate/0a9790198ad274bad3ea0c1649d06d71.png)
<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 Addmethod. 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:
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.
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.