Introduction
MVVM - Model - View & ViewModel
Model is the DBAccess layer, View is Presentation & ViewModel is the BusinessLogic layer.
ICommand is an interface between the Presentation & the BusinessLogic layer.
Whenever any button is pressed on the screen, XAML has its code-behind ButtonClick event. But in MVVM architecture, there is no room for code-behind to keep the application loosely coupled, so ICommand was introduced. It is a way to trigger ViewModel when action is performed on View.
Let's start the cooking process, we need our main ingredient, RelayCommand.
RelayCommand is going to be inherited from ICommand.
ICommand has one event: EventHandler CanExecuteChanged and 2 methods: Execute & CanExecute
- An Event
EventHandler CanExecuteChanged: This event runs asynchronously in the background, It keeps track if logic in the method CanExecute() has changed. - CanExecute method
CanExecute plays a vital role. Take a scenario, let's say you have a user registration page & it has some TextBoxes and one Register button at the bottom. Initially, the button has to be disabled. The button will only be enabled when a user starts filling the form. Otherwise, it is useless for a button to work if
it has nothing to process. Don't worry we will see this in action. - Execute method
The execution of an Execute method depends on what CanExecute returns.
Like we said above, if the user starts filling up a form then Register Button will be enabled and then after clicking on a button we will process the information that the user has entered.
But the Register Button remains disabled until the user starts typing. This means our Execute method is not going to be triggered unless and until we have some information to process.
One is for Execute which will be Action delegate because this method is not gonna return a value.
CanExecute will be a fun delegate because this method always has to returns something because everything else depends on it.
If you want to learn about Action, Fun & Predicate delegates, you can visit Delegates Explained.
Our final implementation of RelayCommand will look like this:
- using System;
- using System.Windows.Input;
- namespace A
- {
- public class RelayCommand : ICommand
- {
- Action<object> _execute;
- Func<object, bool> _canExecute;
- public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
- {
- _execute = execute;
- _canExecute = canExecute;
- }
- public bool CanExecute(object parameter)
- {
- if (_canExecute != null)
- {
- return _canExecute(parameter);
- }
- else
- {
- return false;
- }
- }
- public event EventHandler CanExecuteChanged {
- add
- {
- CommandManager.RequerySuggested += value;
- }
- remove
- {
- CommandManager.RequerySuggested -= value;
- }
- }
- public void Execute(object parameter)
- {
- _execute(parameter);
- }
- }
- }
The flow of data:
3 Fields:
- UserName
- Age
- EmailId
ResetButton - ICommad binded: ResetButtonClicked
Validations
RegisterButton will only be enabled if the user enters a UserName
ResetButoon will only be enabled if any of the TextBoxes have some value to reset.
1st MainWindow.xaml
See how RegisterButton & ResetButton are bound:
- <Button x:Name="ButtonRegister"
- Height="20"
- Width="100"
- Content="Register"
- HorizontalAlignment="Center"
- Margin="20 10 0 0"
- Command="{Binding RegisterButtonClicked}"/>
- <Button x:Name="ButtonReset"
- Height="20"
- Width="100"
- Content="Reset"
- HorizontalAlignment="Center"
- Margin="20 10 0 0"
- Command="{Binding ResetButtonClicked}"/>
Complete View
- <Window x:Class="A.MainWindow"
- xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
- xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
- xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- mc:Ignorable="d"
- Title="MainWindow" Height="200" Width="320">
- <Window.Resources>
- <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
- </Window.Resources>
- <Grid HorizontalAlignment="Center">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="5*"/>
- </Grid.RowDefinitions>
- <Grid.ColumnDefinitions>
- <ColumnDefinition Width="Auto"/>
- <ColumnDefinition Width="Auto"/>
- </Grid.ColumnDefinitions>
- <Label x:Name="LabelUserName"
- Content="User Name:"
- Margin="0 10 0 0"/>
- <Label x:Name="LabelAge"
- Content="Age:"
- Grid.Row="1"/>
- <Label x:Name="LabelEmailId"
- Content="Email:"
- Grid.Row="2"/>
- <TextBox x:Name="TextBoxUserName"
- Text="{Binding UserName}"
- Height="20"
- Width="150"
- Margin="0 10 0 0"
- Grid.Column="1"/>
- <TextBox x:Name="TextBoxAge"
- Text="{Binding Age}"
- Height="20"
- Width="150"
- Grid.Column="1"
- Grid.Row="1"/>
- <TextBox x:Name="TextBoxEmail"
- Text="{Binding EmailId}"
- Height="20"
- Width="150"
- Grid.Column="1"
- Grid.Row="2"/>
- <StackPanel x:Name="StackPanelButtons"
- Orientation="Horizontal"
- Grid.ColumnSpan="2"
- Grid.Row="3" >
- <Button x:Name="ButtonRegister"
- Height="20"
- Width="100"
- Content="Register"
- HorizontalAlignment="Center"
- Margin="20 10 0 0"
- Command="{Binding RegisterButtonClicked}"/>
- <Button x:Name="ButtonReset"
- Height="20"
- Width="100"
- Content="Reset"
- HorizontalAlignment="Center"
- Margin="20 10 0 0"
- Command="{Binding ResetButtonClicked}"/>
- </StackPanel>
- <TextBlock x:Name="TextBlockMessage"
- HorizontalAlignment="Center"
- Margin="20 8 0 0"
- Grid.Row="4"
- Grid.ColumnSpan="2">
- <TextBlock.Style>
- <Style TargetType="TextBlock">
- <Setter Property="Text"
- Value="Enter details to register!">
- </Setter>
- <Style.Triggers>
- <DataTrigger Binding="{Binding IsButtonClicked}" Value="True">
- <Setter Property="Text"
- Value="{Binding UserName, StringFormat='User: {0} is successfully registered!'}">
- </Setter>
- </DataTrigger>
- </Style.Triggers>
- </Style>
- </TextBlock.Style>
- </TextBlock>
- </Grid>
- </Window>
Now MainWindowViewModel.
String properties
UserName, Age & EmailId represents 2 TextBoxes in UI
Based on IsButtonClicked's boolean value, our XAML will decide what message to show (style applied on TextBlock x:Name="TextBlockMessage") command for both buttons:
- public ICommand RegisterButtonClicked { get; set; }
- public ICommand ResetButtonClicked { get; set; }
Constructor where commands are initialized:
- #region Constructor
- public MainWindowViewModel()
- {
- RegisterButtonClicked = new RelayCommand(RegisterUser, CanUserRegister);
- ResetButtonClicked = new RelayCommand(ResetPage, CanResetPage);
- }
- #endregion
- using Prism.Commands;
- using Prism.Mvvm;
- using System.Windows.Input;
- namespace WPFAPP
- {
- class MainWindowViewModel : BindableBase
- {
- #region Properties
- private string _userName;
- public string UserName
- {
- get { return _userName; }
- set { SetProperty(ref _userName, value); }
- }
- private string _age;
- public string Age
- {
- get { return _age; }
- set { SetProperty(ref _age, value); }
- }
- private string _emailId;
- public string EmailId
- {
- get { return _emailId; }
- set { SetProperty(ref _emailId, value); }
- }
- private bool _isButtonClicked;
- public bool IsButtonClicked
- {
- get { return _isButtonClicked; }
- set { SetProperty(ref _isButtonClicked , value); }
- }
- #endregion
- #region ICommands
- public ICommand RegisterButtonClicked { get; set; }
- public ICommand ResetButtonClicked { get; set; }
- #endregion
- #region Constructor
- public MainWindowViewModel()
- {
- RegisterButtonClicked = new RelayCommand(RegisterUser, CanUserRegister);
- ResetButtonClicked = new RelayCommand(ResetPage, CanResetPage);
- }
- #endregion
- #region Event Methods
- private void RegisterUser(object value)
- {
- IsButtonClicked = true;
- }
- private bool CanUserRegister(object value)
- {
- if (string.IsNullOrEmpty(UserName))
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- private void ResetPage(object value)
- {
- IsButtonClicked = false;
- UserName = Age = EmailId = "";
- }
- private bool CanResetPage(object value)
- {
- if (string.IsNullOrEmpty(UserName)
- || string.IsNullOrEmpty(EmailId)
- || string.IsNullOrEmpty(Age))
- {
- return false;
- }
- else
- {
- return true;
- }
- }
- #endregion
- }
- }
Very well, now let's check out the output:

Conclusion
In this article:
- We learned how to create RelayCommands
- How to bind them in MVVM architecture
- How to use CanExecute & Execute methods
- We achieved dependency between modules by keeping Presentation & BusinessLogic loosely coupled
We now support loosely coupled applications, all the very best to you.
I believe that now you will be able to successfully implement a WPF application using commands.

Mehrdad ZandiPosted Jul 21, 2023, 7:57 AM
Very fine description thank you
Jeffrey CountsPosted Jul 23, 2021, 8:11 PM
This was an incredibly helpful article/example of how ICommand works. One thing though - I don't see where you are binding the MainWindow to the MainWindowViewModel?
Nikos nPosted Nov 26, 2020, 3:12 PM
Well written article ! I have a question. What if the properties belong to another class and not in ViewModel. For example if there was a Model Class User where the username property was located ? In a real world example not all the properties that we want to validate are in the same class as the ViewModel and the ICommands. How would be able to trigger the CanExecute method then? Thanks !
greg dorianPosted Sep 18, 2020, 6:00 PM
Hi Rikam great Article!! but do you have source code? in github maybe? another thing is that you use prism what is for?