How to Implement MVVM, INotifyChanged and ICommand in a Silverlight Application
TweetIn this post we will be converting an application that adds two numbers together to use the MVVM (Model-View-ViewModel) pattern as part of the How To Refactor And Build Better Microsoft Silverlight Applications series.
The code used in this post can be downloaded here.
Why MVVM?
While I could write about what MVVM is, I would just be repeating what Josh Smith and Jesse Liberty have already covered in the ‘WPF Apps With The Model-View-ViewModel Design Pattern’ MSDN article and the ‘MVVM – It’s Not Kool-Aid*’ blog post.
I like the MVVM pattern because it helps me to write code and develop solutions that:
- keeps my code behind files as code free as possible
- can be unit tested
- are simpler to read and understand
- are less headache to maintain
- adhere to good programming principles
- make validation easier to implement
It’s important to remember MVVM isn’t the solution to every problem. If you don’t need to use it, don’t, do whatever is right for your application.
The application pre MVVM
In the current application the XAML looks like this
<Grid x:Name="LayoutRoot" Background="White" Height="100" Width="350">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Text="0" Height="25" TextAlignment="Right" x:Name="tbFirstValue"/>
<TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
<TextBox Grid.Column="2" Text="0" Height="25" TextAlignment="Right" x:Name="tbSecondValue"/>
<TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
<TextBlock Grid.Column="4" Text="0" Height="25" TextAlignment="Left" x:Name="tbResult"/>
<Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" x:Name="btnCalculate" Click="btnCalculate_Click" />
</Grid>
and the code behind looks like this
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
tbResult.Text = (Convert.ToInt32(tbFirstValue.Text) + Convert.ToInt32(tbSecondValue.Text)).ToString();
}
}
It’s all about the ViewModel
The name of the ViewModel for this application will be CalculatorViewModel.
If you follow the convention of naming the ViewModel using the name of the consumer who will be using it, knowing what the ViewModel is used for is easier as the application grows.
This will also help to ensure you do not use the same ViewModel for multiple controls, something which is considered to be a best practice.
Setting the CalculatorViewModel as the data context of the Silverlight user control is usually done in one of two ways (some people implement service locators or use a provider).
setting the ViewModel as the DataContext in the code behind
public CalculatorPage()
{
InitializeComponent();
DataContext = new CalculatorViewModel();
}
or setting the ViewModel as the DataContext in XAML
<UserControl.DataContext>
<local:CalculatorViewModel/>
</UserControl.DataContext>
INotifyChanged
By implementing the INotifyChanged interface (or inheriting from a base class which implements it), events can be raised when a property value changes.
For the calculator example events will be used to update the user interface when the values for the two input numbers or the calculated result change.
The code below shows how the OnPropertyChanged method is called in the property setters to raise the PropertyChangedEventHandler.
private string _firstValue;
private string _secondValue;
private string _result;
public event PropertyChangedEventHandler PropertyChanged;
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
OnPropertyChanged("SecondValue");
}
}
public string Result
{
get { return _result; }
private set
{
_result = value;
OnPropertyChanged("Result");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
The next step is to change the text controls in the XAML file to bind to the properties in the ViewModel
<TextBox Grid.Column="0" Text="{Binding FirstValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
<TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
<TextBox Grid.Column="2" Text="{Binding SecondValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
<TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
<TextBlock Grid.Column="4" Text="{Binding Result, Mode=OneWay}" Height="25" TextAlignment="Left"/>
Notice how the binding mode on the text boxes are two way but the result text block is only one way.
We need to use a two way binding to be able to update the ViewModel with the values the user enters.
As the user cannot enter a value in the result text block the binding only needs to be one way.
If you want more information about data binding check out the Data Binding Overview article on MSDN.
Commands in Silverlight 4
New in Silverlight 4 are commands (WPF already had them). Commands enable us to replace the click event for the calculate button in the XAML file with a command as shown below.
<Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" Command="{Binding CalculateCommand}" />
The command binds to a CalculateCommand property in the ViewModel which looks like this
private readonly ICommand _calculateCommand;
public ICommand CalculateCommand
{
get { return _calculateCommand; }
}
So how does the command know what to do?
The answer is by using a RelayCommand (which implements the ICommand interface) and passing a method (which adds two values together) in its constructor. A relay command allows for cleaner command implementation in ViewModel classes.
The code for the RelayCommand is shown below (I can’t take any credit for this as I’ve taken it from Josh Smiths MSDN article).
public class RelayCommand : ICommand
{
private Action _handler;
public RelayCommand(Action handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
}
The code below shows the calculate method and how the relay command is set up in the ViewModels’ constructor
public CalculatorViewModel()
{
_calculateCommand = new RelayCommand(Calculate){IsEnabled = true};
}
private void Calculate()
{
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
}
So what have we achieved?
Given that all we are doing here is adding two numbers together the effort of implementing the MVVM pattern looks to be a lot of work.
The important thing to take away is what an MVVM ViewModel looks like without the use of any third party frameworks such the MVVM Light Toolkit. The code in this post only uses the libraries that ship with Microsoft Silverlight 4.
The class diagram for the ViewModel looks like this

and the complete code listing for the ViewModel is shown below
using System;
using System.ComponentModel;
using System.Windows.Input;
namespace SilverlightCalculator
{
public class CalculatorViewModel : INotifyPropertyChanged
{
private string _firstValue;
private string _secondValue;
private string _result;
private readonly ICommand _calculateCommand;
public event PropertyChangedEventHandler PropertyChanged;
public CalculatorViewModel()
{
_calculateCommand = new RelayCommand(Calculate){IsEnabled = true};
}
private void Calculate()
{
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
}
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
OnPropertyChanged("SecondValue");
}
}
public string Result
{
get { return _result; }
private set
{
_result = value;
OnPropertyChanged("Result");
}
}
public ICommand CalculateCommand
{
get { return _calculateCommand; }
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
}
With the foundation code in place adding additional properties or commands is easy.
While MVVM can be used and implemented in the wrong way (as with every pattern), by applying good software craftsmanship skills a Silverlight or WPF application using the MVVM pattern will encourage you to adopt best practices (as we will see later in the series).
If you have arrived here from a search engine, this post is part of series about refactoring Silverlight applications. So if you’re thinking calculating numbers this way is a ‘code smell’, see how this can be resolved by applying the Single Responsibility Principle to View Models in Silverlight and WPF.
Pingback: Những ví dụ Cụ thể về WPF Command Model « Tô Mỳ Minh Duy (CTTMMD)