Table of Contents
Introduction
Model View ViewModel is the golden child of WPF, allowing a developer to completely separate their application code from any UI dependencies.
This means an application can be easily be re-skinned, and it also makes an application much easier to test.
The View represents any front-end user interface controls (Window, Page, UserControl), the Model represents the classes used in the application, and the ViewModel is the middle-man that requests, molds and exposes the data, as properties and commands.
About the Sample Project
This is article is linked to a TechNet sample project that you can download and explore.
It covers many basic concepts of MVVM, and some of the common pitfalls and solutions.
The idea is to download the sample, run it to see each example, then read through this, along side the code.
By the time you have finished, you should know most of what you need to know :)
DOWNLOAD : http://gallery.technet.microsoft.com/Easy-MVVM-Examples-48c94de3
If you're looking for more good WPF examples, you will probably enjoy my other Gallery sample projects. all I ask is that you rate (star) them, thanks.
Classic INotifyPropertyChanged
This first example is the classic MVVM configuration, implementing INotifyPropertyChanged in a base class (ViewModelBase)
class
ViewModelBase : INotifyPropertyChanged
{
internal
void
RaisePropertyChanged(
string
prop)
{
if
(PropertyChanged !=
null
) { PropertyChanged(
this
,
new
PropertyChangedEventArgs(prop)); }
}
public
event
PropertyChangedEventHandler PropertyChanged;
This base class contains the common code used by all properties of all other derived ViewModels, one is shown below.
string
_TextProperty1;
public
string
TextProperty1
{
get
{
return
_TextProperty1;
}
set
{
if
(_TextProperty1 != value)
{
_TextProperty1 = value;
RaisePropertyChanged(
"TextProperty1"
);
}
}
}
As you can see, it looks like a standard CLI object, but with the extra RaisePropertyChanged method in the setter.
In example 1, the ViewModel is attached by the View itself, in XAML. Notice this is possible because the ViewModel does not need any parameters in it's constructor.
<
Window
. . .
xmlns:vm
=
"clr-namespace:MvvmExample.ViewModel"
DataContext
=
"{DynamicResource ViewModelMain}"
>
<
Window.Resources
>
<
vm:ViewModelMain
x:Key
=
"ViewModelMain"
/>
</
Window.Resources
>
There is a ListBox, DataGrid and ComboBox, ALL with ItemsSource to the same collection, and the same SeletedItem.
Changes to the values of any of the properties in the DataGrid are reflected across all controls.
As you change the selected Person in any of these controls, you will see all three change together.
A TextBox and TextBlock share the same property, so changes in the TextBox reflect in the TextBlock.
Click the button to add a user, it shows in all three controls.
Although many would think that this is all due to our 'enriched' INPC classes, most of this is actually triggered by changing the values through the UI, as explained later.
Only the Add user command relies on PropertyChanged events, and they come from the changing ObservableCollection.
Switching Windows from Event Handlers in Code-behind
A traditional method of triggering functions and navigating from one window to another is using code-behind event handlers.
This means your code is tightly coupled with the user interface.
private
void
Button_Click(
object
sender, RoutedEventArgs e)
{
var win =
new
Window1 { DataContext =
new
ViewModelWindow1(tb1.Text) };
win.Show();
this
.Close();
}
The most common first question in MVVM is how to call methods of a control like Window.Close() from a ViewModel.
This is shown in the next example.
DataContext Made in Code
The second example simply shows how you can attach the ViewModel to the DataContext from code, done by the previous window shown above, as this window was created.
var win =
new
Window1 { DataContext =
new
ViewModelWindow1(tb1.Text) };
In this example, the ViewModel takes a string parameter in it's constructor. Work done in the constructor is BEFORE binding occurs, so we can populate private variables:
public
ViewModelWindow1(
string
lastText)
{
_TestText = lastText;
This ViewModel is derived from ViewModelMain, with an extra public property and command to pull a value from the base class and update this new property.
The Button command passes in a value from the UI in the CommandParameter. This saves us having to reference controls directly from code.
<
Button
Content
=
"Change Text"
Command
=
"{Binding ChangeTextCommand}"
CommandParameter
=
"{Binding SelectedItem, ElementName=dg1}"
/>
In this example, the selected person is used to make the value for public property TestText.
This command is triggered AFTER the page has finished binding, so we target the public property, so the PropertyChanged event is triggered.
This is so the bindings related to that property know that they need to update, otherwise changes will never be reflected in the UI.
void
ChangeText(
object
selectedItem)
{
if
(selectedItem ==
null
)
TestText =
"Please select a person"
;
else
{
var person = selectedItem
as
Person;
TestText = person.FirstName +
" "
+ person.LastName;
}
}
Closing Windows from the ViewModel
This second example shows a nice way to close a window from a ViewModel, using an Attached Behavior.
The "close window" behavior is added from an attached property called DialogResult.
public
static
class
DialogCloser
{
public
static
readonly
DependencyProperty DialogResultProperty =
DependencyProperty.RegisterAttached(
"DialogResult"
,
typeof
(
bool
?),
typeof
(DialogCloser),
new
PropertyMetadata(DialogResultChanged));
private
static
void
DialogResultChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var window = d
as
Window;
if
(window !=
null
) window.Close();
}
public
static
void
SetDialogResult(Window target,
bool
? value)
{
target.SetValue(DialogResultProperty, value);
}
}
This is then attached to the Windows that we want to control:
<
Window
x:Class
=
"MvvmExample.ViewModel.Window1"
WindowStartupLocation
=
"CenterScreen"
Title
=
"Window1"
Height
=
"300"
Width
=
"400"
xmlns:helpers
=
"clr-namespace:MvvmExample.Helpers"
helpers:DialogCloser.DialogResult
=
"{Binding
CloseWindowFlag}"
>
As all our Windows use ViewModels, which all inherit from ViewModelBase, we can put this generic window closer property and Close method in the base class:
bool
? _CloseWindowFlag;
public
bool
? CloseWindowFlag
{
get
{
return
_CloseWindowFlag; }
set
{
_CloseWindowFlag = value;
RaisePropertyChanged(
"CloseWindowFlag"
);
}
}
public
virtual
void
CloseWindow(
bool
? result =
true
)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new
Action(() =>
{
CloseWindowFlag = CloseWindowFlag ==
null
?
true
: !CloseWindowFlag;
}));
}
Our actual ViewModel can now handle navigation and closing windows as shown:
void
NextExample(
object
parameter)
{
var win =
new
Window2();
win.Show();
CloseWindow();
}
Using DependencyObject instead of INPC
This example shows the alternative to INotifyPropertyChanged - DependencyObject and Dependency Properties.
class
ViewModelWindow2 : DependencyObject
{
public
Person SelectedPerson
{
get
{
return
(Person)GetValue(SelectedPersonProperty); }
set
{ SetValue(SelectedPersonProperty, value); }
}
public
static
readonly
DependencyProperty SelectedPersonProperty =
DependencyProperty.Register(
"SelectedPerson"
,
typeof
(Person),
typeof
(ViewModelWindow2),
new
UIPropertyMetadata(
null
));
Dependency Properties are considered a "richer" method of binding, as the Register method also has several overloads for PropertyChanged and Coerce delegate methods.
The main drawback to Dependency Properties for general MVVM use is they need to be handled on the UI layer.
For more on the INPC vs DP debate, read the following:
Controlling an Application through CanExecute
This example also shows how a command can also control whether a button is enabled or not, through it's CanExecute delegate.
This again moves away from controller and more into behavior.
The action cannot even be triggered if conditions are not met, and this is clear to the user as the button is disabled.
We are not using the command parameter in this example, but relying on a ViewModel property to be populated with the selected item.
If there is none, the CanExecute method returns false, which
disables the button.
All encapsulated in the command, nice clean code.
public ViewModelWindow2()
{
People = FakeDatabaseLayer.GetPeopleFromDatabase();
NextExampleCommand = new RelayCommand(NextExample, NextExample_CanExecute);
}
bool NextExample_CanExecute(object parameter)
{
return SelectedPerson != null;
}
Closing with Attached Property via Dependency Property
To close the window in this example, we still use the Attached Property in the Window XAML, but the property is a
Dependency Property in the ViewModel.
public
bool
? CloseWindowFlag
{
get
{
return
(
bool
?)GetValue(CloseWindowFlagProperty); }
set
{ SetValue(CloseWindowFlagProperty, value); }
}
// Using a DependencyProperty as the backing store for CloseWindowFlag. This enables animation, styling, binding, etc...
public
static
readonly
DependencyProperty CloseWindowFlagProperty =
DependencyProperty.Register(
"CloseWindowFlag"
,
typeof
(
bool
?),
typeof
(ViewModelWindow2),
new
UIPropertyMetadata(
null
));
Used simply as follows:
void
NextExample(
object
parameter)
{
var win =
new
Window3(SelectedPerson);
win.Show();
CloseWindowFlag =
true
;
}
Using POCO Objects with MVVM
A POCO class in WPF/MVVM terms is one that does not provide any PropertyChanged events.
class
PocoPerson
{
public
string
FirstName {
get
;
set
; }
public
string
LastName {
get
;
set
; }
public
int
Age {
get
;
set
; }
}
This would usually be legacy code modules, or converting from WinForms.
This next example demonstrates how things start to break, when you don't use PropertyChanged events.
At first, everything seems fine. Selected item is updated in all, you can change properties of existing people, and add new people through the DataGrid.
Those actions are all UI based actions, which change Dependency Properties like
TextBox.Text, and automatically fire the PropertyChanged event.
However, the TextBox should actually be showing a
time stamp, as set by the code behind Dispatcher Timer.
public
ViewModelWindow3(Person person)
{
. . . snip . . .
timer =
new
DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick +=
new
EventHandler(timer_Tick);
timer.Start();
}
void
timer_Tick(
object
sender, EventArgs e)
{
TextProperty1 = DateTime.Now.ToString();
}
Furthermore, clicking the Button to add a new person does not seem to work, but it did.
If you then try to add a user in the DataGrid, the binding updates, and shows the previously added user.
All a bit broken.
Custom Event Self-close Hack
Just as an alternative, this ViewModel has a custom event, to signify closure, which is handled in code behind when the ViewModel is attached.
public
Window3(Person person)
{
InitializeComponent();
var vm =
new
ViewModelWindow3(person);
DataContext = vm;
vm.CloseWindowEvent +=
new
System.EventHandler(vm_CloseWindowEvent);
}
void
vm_CloseWindowEvent(
object
sender, System.EventArgs e)
{
this
.Close();
}
Fixing One Property to Show the Difference
The following window is almost identical to the previous POCO example. However
TextProperty1 now triggers a PropertyChanged event in it's setter.
set
{
if
(_TextProperty1 != value)
{
_TextProperty1 = value;
RaisePropertyChanged(
"TextProperty1"
);
//The fix
}
}
Now you will find the time stamp property shows through onto the TextBox as shown below.
However, with events coming from the INPC interface, the other UI bindings are now even more broken.
(Try the sample project)
A Cleaner 'Interface' Way to Close the Window
The behaviour of closing a window, could happily be kept with the window, if you believe that is where it belongs.
One way of always assuring any ViewModel has the expected event shown above would be to make our ViewModels (ideally in the ViewModelBase) inherit an
interface that defines the event.
We can then safely cast any ViewModel back to this interface, and attach a handler to the expected event.
public
Window4()
{
InitializeComponent();
DataContextChanged +=
new
DependencyPropertyChangedEventHandler(Window4_DataContextChanged);
}
void
Window4_DataContextChanged(
object
sender, DependencyPropertyChangedEventArgs e)
{
var dc = DataContext
as
IClosableViewModel;
dc.CloseWindowEvent +=
new
EventHandler(dc_CloseWindowEvent);
}
How to Consume a Closed Business Object (database layer, web service)
The most important message to learn from all of this is that if you can convert the base (model) classes that you use to INPC properties, DO SO NOW. You will save yourself a world of pain, unnecessary data marshalling through wrappers, and
a whole load of code that can introduce bugs and dependencies to your implementation.
But what if you have a Business Object that handles all the work, like an
existing database module, or web service client?
In this case you have to fall back on wrappers and polling.
This final example ViewModel acts as a shepherd between our front end controls and a "personnel management" business object. It only exposes the following methods:
- GetEmployees()
- AddPerson(Person)
- DeletePerson(Person)
- UpdatePerson(Person)
It also has a public POCO string property ReportTitle.
Finally, there a "Status" enum (Offline, Online) which periodically toggles from a [background thread] Timer.
Wrapping POCOs
Firstly, we need to marshal the data in and out of the business object. We need to wrap the data in marshalling properties.
As we only have a GET method for employee list, we only need a public property with a get method, to populate our DataGrid:
ObservableCollection<PocoPerson> _People;
public
ObservableCollection<PocoPerson> People
{
get
{
_People =
new
ObservableCollection<PocoPerson>(personnel.GetEmployees());
return
_People;
}
}
The public string property "Report Title" is a two-way pass-through wrapper (getter and setter). It marshals the values in and out.
This takes us back to our first POCO example, where this is sufficient for some operations, but changes to the "back-end" data, will not automatically be reflected in the UI.
There is a Label also bound to this property, but again it only works because the change was UI initiated, as explained in earlier examples.
public
string
ReportTitle
{
get
{
return
personel.ReportTitle;
}
set
{
if
(personel.ReportTitle != value)
{
personnel.ReportTitle = value;
RaisePropertyChanged(
"ReportTitle"
);
}
}
}
Polling POCOs
The final property (BoStatus) represents the business object "Status" property (personel.Status), but this value is constantly updated by another thread, so we would normally miss the updates in the user interface.
The only answer is to poll the property for changes.
BoStatus is therefore not a wrapper, but a store of the "last known" value.
MvvmExample.Model.PersonelBusinessObject.StatusType _BoStatus;
public
MvvmExample.Model.PersonelBusinessObject.StatusType BoStatus
{
get
{
return
_BoStatus;
}
set
{
if
(_BoStatus != value)
{
_BoStatus = value;
RaisePropertyChanged(
"BoStatus"
);
}
}
}
We use a Timer to frequently check the property for changes. This may seem expensive, but it's really not, in computer processor terms.
When we detect a change, we update the Public property BoStatus, which saves the new value locally, and fires the PropertyChanged event.
Anything consuming this property will update their bindings, and call the getter to pick up the new value.
void
CheckStatus(
object
sender, EventArgs e)
{
if
(_BoStatus != personel.Status)
BoStatus = personel.Status;
}
Using the CRUD methods of our business object is really down to your own personal design and implementation.
However, as a final example, I included a very simple method for doing this, with practically no code!
Virtually Codeless Master/Detail CRUD Control
This example shows a complete and virtually codeless master/detail, CRUD control (for databases, web services, etc)
By master/detail, we mean there is a master list of objects. You then select a list item to get the item details in a separate box.
By CRUD, we mean Create, Update and
Delete functionality. The three things you do to objects in a collection, or a database.
Normally, in a big application, we would design a stand-alone user control for an edit form, but here is a quick trick to produce the whole, fully wired edit form, using the
ItemsTemplate for an ItemsControl.
The actual edit grid is a DataTemplate, instead of an actual control. This
DataTemplate is used as the ItemTemplate for the
ItemsControl:
<
ItemsControl
BindingGroup
=
"{Binding UpdateBindingGroup, Mode=OneWay}"
ItemTemplate
=
"{StaticResource UserGrid}"
ItemsSource
=
"{Binding SelectedPerson, Converter={StaticResource SelectedItemToItemsSource}}"
/>
The ItemsSource is tied to the SelectedPerson property of our ViewModel.
If you were just editing, and not adding new users, you could bind this directly to the SelectedItem property of the DataGrid, but you will see later why we don't.
A BindingGroup is defined on the ItemsControl, which we use later to cancel or commit changes from the form.
ItemsSource expects a collection, rather than SelectedItem (SelectedPerson). So to make this trick work, we use a simple converter to wrap the selected person into a collection.
public
class
SelectedItemToItemsSource : IValueConverter
{
public
object
Convert(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
if
(value ==
null
)
return
null
;
return
new
List<
object
>() { value };
}
public
object
ConvertBack(
object
value, Type targetType,
object
parameter, System.Globalization.CultureInfo culture)
{
throw
new
NotImplementedException();
}
}
This method means that if there is no selected item, there is no edit form.
This removes the need for visibility converters, or triggers to show & hide the form!
How to Bind and When to Update
Binding to properties of the selected person, is only the immediate DataContext of the generated item - direct and easy.
<
TextBox
Text
=
"{Binding FirstName, BindingGroupName=Group1, UpdateSourceTrigger=Explicit}"
Grid.Column
=
"1"
/>
However, to get back to the ViewModel and update our "Personnel" Business Object, we need to traverse further up the VisualTree, for which we use RelativeSource:
<
Button
Foreground
=
"Red"
Content
=
"Cancel"
Command
=
"{Binding DataContext.CancelCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Margin
=
"4,0"
/>
This binding traverses back, looking for the first instance of the ItemsControl. We then refer to the properties via it's DataContext.
To allow us to cancel an edit, the binding's UpdateSourceTrigger is changed to Explicit.
This prevents any updates of the source data, until we manually call an Update on the bindings.
As these are auto-generated controls and bindings, we would normally have had to use VisualTreeHelper to hunt for the controls in the VisualTree, so that we can locate and call the Update method on the bindings... Yuk... o_O
Instead we are using the Binding Group we earlier attached to the ItemsControl.
Each binding in the DataTemplate also includes a reference to this group name:
<
TextBox
Text
=
"{Binding . . . BindingGroupName=Group1, . . ." />
The trick to use this in an MVVM scenario is that this BindingGroup needs to be defined in the ViewModel, and passed INTO the ItemsControl, through binding.
It needs to be already waiting, if it is to be used by the DataTemplate bindings.
<
ItemsControl
BindingGroup
=
"{Binding UpdateBindingGroup, Mode=OneWay}"
. . . />
This is then just another property of our ViewModel, that we can use in the ViewModel and is updated from the UI, as bindings are created and destroyed by the ItemsControl.
BindingGroup _UpdateBindingGroup;
public
BindingGroup UpdateBindingGroup
{
get
{
return
_UpdateBindingGroup;
}
set
{
if
(_UpdateBindingGroup != value)
{
_UpdateBindingGroup = value;
RaisePropertyChanged(
"UpdateBindingGroup"
);
}
}
}
public
ViewModelWindow5()
{
. . .
UpdateBindingGroup =
new
BindingGroup { Name =
"Group1"
};
In our command handling methods, we can update or cancel the changes from our ViewModel.
void
DoCancel(
object
param)
{
UpdateBindingGroup.CancelEdit();
void
DoSave(
object
param)
{
UpdateBindingGroup.CommitEdit();
Create, Update, Delete Logic
To add a new user, we simply create a new "placeholder" object into SelectedPerson.
This shows and populates the form with the new user object, which we can fill in.
This is why we bind the ItemsControl ItemsSource to SelectedPerson instead of directly to DataGrid.SelectedItem.
If new user deleted/cancelled, we simply set SeletedPerson back to null, which disposes of the object.
If existing user cancelled, we call CancelEdit on the BindingGroup.
If new user saved, we call AddUser on the Business Object, then trigger PropertyChanged on the People collection, for a fresh list from the Business Object.
If existing user saved, we call UpdateUser on the Business Object and ComitEdit on the BindingGroup
If existing user deleted, we call DeleteUser on the Business Object, then trigger PropertyChanged on the People collection, for a fresh list from the Business Object.
For example, here is what we do for the Save command:
void
DoSave(
object
param)
{
UpdateBindingGroup.CommitEdit();
var person = SelectedPerson
as
PocoPerson;
if
(SelectedIndex == -1)
{
personel.AddPerson(person);
RaisePropertyChanged(
"People"
);
// Update the list from the data source
}
else
personel.UpdatePerson(person);
SelectedPerson =
null
;
}
CommitEdit updates the properties in the existing collection, if you are updating an existing Person.
It does not updating the list. CommitEdit will update the existing data and hence the user interface, so we don't need to request an update of the whole list.
I hope this article has helped to explain the Role of PropertyChanged events in MVVM, and how to wire up your controls and navigation.
Please give a couple of seconds, to rate/star the Gallery sample.
DOWNLOAD : http://gallery.technet.microsoft.com/Easy-MVVM-Examples-48c94de3
Many more sample projects available HERE!!!
If you are learning MVVM, don't forget to grab this essential set of classes