Easy MVVM examples (in extreme detail)

Easy MVVM examples (in extreme detail)

This article discusses the various methods and tricks used in MVVM, to enable a developer to completely separate the user interface from the code. It demonstrates all the basics with easy examples to follow, in a downloadable project.


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.

 

Return to Top


 

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.

Return to Top



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();
}


Return to Top



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;
}

   

Return to Top


 

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);
}

Return to Top



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?

This may therefore be a "closed object" that you cannot enrich with INPC on it's properties.

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
 

Return to Top


Sort by: Published Date | Most Recent | Most Useful
Comments
Page 1 of 1 (1 items)