Today, we will talk about WPF Commands. When I develop a new application in WPF, I try to follow the MVVM Pattern (Model-View-ViewModel).
To help me, I use the toolkit shared by Laurent Bugnion: Mvvm Light Toolkit (Galasoft). If you don’t use it, no matter, the idea is the same with or without a toolkit.
To show you how to use commands, we will create a simple application that saves some information about a person.
So a person can be described using this field:
LastName
FirstName
Address
ZipCode
City
A Save button would call the SaveCommand
and a Cancel button would call CancelCommand
.
So, we first create our model, adding a Person
class in Model directory. Keep things simple:
public class Person
{
public string Nom { get; set; }
public string Prenom { get; set; }
public string Adresse { get; set; }
public string CodePostal { get; set; }
public string Ville { get; set; }
}
Then we create our ViewModel
: I will simply modify the one created by the template for MainWindow
. I just edit it to add properties needed:
public class MainViewModel : ViewModelBase
{
private readonly Person _newPerson;
private const string LastNamePropertyName = "LastName";
public string LastName
{
get { return _newPerson.LastName; }
set
{
_newPerson.LastName = value;
RaisePropertyChanged(LastNamePropertyName);
}
}
private const string FirstNamePropertyName = "FirstName";
public string FirstName
{
get
{
return _newPerson.FirstName;
}
set
{
_newPerson.FirstName = value;
RaisePropertyChanged(FirstNamePropertyName);
}
}
private const string AddressPropertyName = "Address";
public string Address
{
get
{
return _newPerson.Address;
}
set
{
_newPerson.Address = value;
RaisePropertyChanged(AddressPropertyName);
}
}
private const string ZipCodePropertyName = "ZipCode";
public string ZipCode
{
get
{
return _newPerson.ZipCode;
}
set
{
_newPerson.ZipCode = value;
RaisePropertyChanged(ZipCodePropertyName);
}
}
private const string CityPropertyName = "City";
public string City
{
get
{
return _newPerson.City;
}
set
{
_newPerson.City = value;
RaisePropertyChanged(CityPropertyName);
}
}
public MainViewModel()
{
_newPerson = new Person();
}
}
Let’s create the UI. We will have a simple form in the MainWindow.xaml:
<Grid Height="195">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="42*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="122*" />
<ColumnDefinition Width="296*" />
</Grid.ColumnDefinitions>
<Label Content="LastName" Grid.RowSpan="2" Height="28" HorizontalAlignment="Left"
Margin="40,5,0,0" Name="label1" VerticalAlignment="Top" />
<Label Content="FirstName" Grid.Row="1" Grid.RowSpan="2" Height="28"
HorizontalAlignment="Left" Margin="40,5,0,0" Name="label2"
VerticalAlignment="Top" />
<Label Content="Address" Grid.Row="2" Grid.RowSpan="2" Height="28"
HorizontalAlignment="Left" Margin="40,5,0,0" Name="label3"
VerticalAlignment="Top" />
<Label Content="Code Postal" Grid.Row="3" Grid.RowSpan="2" Height="28"
HorizontalAlignment="Left" Margin="40,5,0,0" Name="label4"
VerticalAlignment="Top" />
<Label Content="City" Grid.Row="4" Grid.RowSpan="3" Height="28"
HorizontalAlignment="Left" Margin="40,5,0,0" Name="label5"
VerticalAlignment="Top" />
<TextBox Grid.Column="1" Grid.RowSpan="2" Height="23" HorizontalAlignment="Left"
Margin="20,5,0,0" Name="textBox1" VerticalAlignment="Top" Width="120"
Text="{Binding Path=LastName}" />
<TextBox Grid.Column="1" Grid.Row="1" Grid.RowSpan="2" Height="23"
HorizontalAlignment="Left" Margin="20,5,0,0" Name="textBox2"
VerticalAlignment="Top" Width="120" Text="{Binding Path=FirstName}" />
<TextBox Grid.Column="1" Grid.Row="2" Grid.RowSpan="2" Height="23"
HorizontalAlignment="Left" Margin="20,5,0,0" Name="textBox3"
VerticalAlignment="Top" Width="120" Text="{Binding Path=Address}" />
<TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left"
Margin="20,5,0,0" Name="textBox4" VerticalAlignment="Top" Width="120"
Text="{Binding Path=City}" />
<TextBox Grid.Column="1" Grid.Row="3" Grid.RowSpan="2" Height="23"
HorizontalAlignment="Left" Margin="20,5,0,0" Name="textBox5"
VerticalAlignment="Top" Width="120" Text="{Binding Path=ZipCode}" />
<Button Content="Save" Grid.Column="1" Grid.Row="6" Height="23"
HorizontalAlignment="Left" Margin="25,10,0,0" Name="button1"
VerticalAlignment="Top" Width="75" />
<Button Content="Cancel" Grid.Column="1" Grid.Row="6" Height="23"
HorizontalAlignment="Left" Margin="120,10,0,0" Name="button2"
VerticalAlignment="Top" Width="75" />
</Grid>
Here is what it should look like:
Now, the main reason of this article: The Commands.
We will create our two commands and then bind them to our buttons.
How do we define a command?
First, the command should implement ICommand
interface.
Then, a Create
method will create the command so that we can use it.
Then, we find two methods: the first one, CanExecute
, would check if the command can be executed and the second one, Execute
, will execute the command.
The Save
Command:
public ICommand SaveCommand
{
get;
internal set;
}
private bool CanExecuteSaveCommand()
{
return !string.IsNullOrEmpty(LastName);
}
private void CreateSaveCommand()
{
SaveCommand = new RelayCommand(SaveExecute, CanExecuteSaveCommand);
}
public void SaveExecute()
{
Person.Save(_newPerson);
}
If we look at the CanExecute
method, we can see that the execution would be allowed only if there is a Lastname
.
We, now, add the creation of the method in the constructor of our ViewModel
:
public MainViewModel()
{
_newPerson = new Person();
CreateSaveCommand();
}
And we bind our command on the Save
button:
<Button Content="Save" Grid.Column="1" Grid.Row="6" Height="23"
HorizontalAlignment="Left" Margin="25,10,0,0" Name="button1"
VerticalAlignment="Top" Width="75" Command="{Binding Path=SaveCommand}" />
Let’s launch the application and test this command.
When the application is launched, the LastName
is, of course, empty. And you can see, the Save
button is disabled and we cannot save:
We add a lastname
and set the focus on the following textbox
and we can observe that the Save button is now enabled. The condition in the CanExecute
returns true
!
If we delete the lastname
and change focus, the button will be disabled again.
Now, we add the Cancel
command. It works the same way as the Save
command but there is no requirement to allow the action. So, we will not used the CanExecute
method:
public ICommand CancelCommand
{
get;
internal set;
}
private void CreateCancelCommand()
{
CancelCommand = new RelayCommand(CancelExecute);
}
public void CancelExecute()
{
LastName = string.Empty;
FirstName = string.Empty;
Address = string.Empty;
ZipCode = string.Empty;
City = string.Empty;
}
In the Execute
method, we empty all the textboxes. Fill in the information and click on the Cancel button, all the textboxes will be cleared.
Don’t forget to call the CreateCancelCommand
method in the constructor and to bind the command to the Cancel
command.
The constructor:
public MainViewModel()
{
_newPerson = new Person();
CreateSaveCommand();
CreateCancelCommand();
}
Cancel button binding:
<Button Content="Cancel" Grid.Column="1" Grid.Row="6" Height="23"
HorizontalAlignment="Left" Margin="120,10,0,0" Name="button2"
VerticalAlignment="Top" Width="75" Command="{Binding Path=CancelCommand}" />
This is a very simple example of how to use Commands in WPF.
Let’s try it!
You can download the source code here