What is MVVM?
MVVM is the most popular architectural pattern used in Windows Presentation Foundation (WPF) and Silverlight. It is designed to make use of specific functions in WPF/Silverlight to better facilitate the separation of View layer development from the rest of the pattern by removing virtually all “code behind” from View layer, taking advantage of Binding Markup Extension from XAML. This separation of roles allows interactive designers to focus on UX needs rather than programming or business logic, allowing for the layers of an application to be developed in multiple work streams.
A MVVM solution consist View as pure XAML with default code-behind implementation. A View Model is declared and initiated somewhere in the XAML with detailed bindings to its properties and commands. Left with Models as the data presentation classes managed by ViewModels.
Now we know that Views should be in pure XAML, and Models are just classes that represent the real state of data. Hence, what is actually in the ViewModel?
To create a ViewModel, we need expose properties and commands required by a View, notify the binding framework when a property needs to reflected in the View, and manage the data underneath.
Exposing Properties and Commands via ViewModel
A ViewModel is responsible for establishing properties required by View from a Model. Say we have a table containing a list of greetings in different languages.
- English, Hello
- Taiwanese(Hokkien), Li-ho
- Mandarin, nǐ hǎo
The model will look like this:
public class Greeting{ public string LanguageName {get;set;} public string Dialogue {get;set;}} |
A ViewModel that makes this model available to a view will look like this:
public class GreetingViewModel : System.ComponentModel.INotifyPropertyChanged{ /// <summary> /// Implement the INotifyPropertyChanged interface (preferred). /// For change notification to occur in a binding between a bound client and a data source. /// </summary> public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; public string LanguageName { get{return _model.LanguageName; } set { _model.LanguageName = value; if(PropertyChanged != null) PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("LanguageName")); } } public string Dialogue { get{return _model.Dialogue;} set { _model.Dialogue = value; if(PropertyChanged != null) PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Dialogue")); } }} |
Notice that in the ViewModel we implement INotifyPropertyChanged? The aim is to notify the binding framework when a property is updated via the set method, the property will then be reflected in the View without extra effort.
Exposing an property in ViewModel seems to be fairly straight forward. One improvement you might make is to write a method to assist the notification. You will find other advance extension that some nice people have came up on the World Wide Web.
/// <summary>/// Implement the INotifyPropertyChanged interface (preferred)./// For change notification to occur in a binding between a bound client and a data source./// </summary>public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;private void NotifyPropertyChanged(string propertyName){ if (PropertyChanged != null) PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));}public string LanguageName{ get { return _model.LanguageName; } set { _model.LanguageName = value; NotifyPropertyChanged("LanguageName"); }}public string Dialogue{ get { return _model.Dialogue; } set { _model.Dialogue = value; NotifyPropertyChanged("Dialogue"); }} |
Now we have a simple ViewModel, let us look at how we would bind it onto XAML.
<UserControl.Resources> <vm:GreetingViewModel x:Key="VM"/></UserControl.Resources><Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource VM}"> <StackPanel> <TextBlock FontWeight="Bold" Text="{Binding Dialogue, Mode=OneWay}"/> <TextBox Text="{Binding LanguageName, Mode=TwoWay}"/> </StackPanel></Grid> |
For more information on Binding visit Binding Markup Extension.