Home > Mini-Tutorial, Patterns & Skills > MVVM – It’s Not Kool-Aid*

MVVM – It’s Not Kool-Aid*

MiniTutorialLogo2

[ Revised with C# and VB.NET code]

Okay, first, understand that I’m in the position of running through the streets yelling at folks “c’mere! ya’ gotta see this!” and what I’m pointing to is the incredible new invention of… a laptop computer. Something that is undeniably amazing and cool, but everyone else on my block has already got one.

Second, and much worse, I’m about to show you how I used a “pattern” that you either have already embraced, or that you’ve been avoiding like the plague because the folks who are running around shouting “MVVM! MVVM!” sound just like the folks who were running around shouting “MVC! MVC!” and “OOP! OOP!” and “COM! COM!”…  you get the idea.

Many of us are still recovering from the last five fads that caused us to go out and buy dozens of books and break our head on the latest/greatest trend, only to have it be “oh so last year” by the time we fully grokked it.

Drinking The Kool Aid*

Kool Aid Man

But this is different. Honest.

Here are three heretical assertions about MVVM:

  1. It is not all that different from what you are already doing
  2. It is not hard to understand or to do
  3. You will write better code, and you’ll write less code.

Typically, when a pattern or practice comes along, there is a steep learning curve, and the cognoscenti will tell you that it takes a very long time to truly master the approach. Feh. And not so, at least not this time. Let’s go over the assertions above, and I’ll explain, briefly, what you need to know to profit from MVVM.

Disclaimer: I’m not saying this is all you’ll ever need to know about MVVM, I’m saying if you know this, you can benefit from MVVM on any non-trivial application, while you’re learning more.While I’m disclaiming, please note that I’m writing very specifically about a Silverlight 4 project and that I’ve been coding with MVVM for about a half hour.

It’s Not All That Different and It’s Not That Hard

We’ve been talking about n-tier development, decoupling, scoping, visibility and related topics since at least 1990. I’m pretty sure that when they were cracking the Enigma machine in World War II, they discussed decoupling the code-breaker module from the UI (did they have UI then?)

MVVM, at its heart has three core concepts, only the third of which is new, but that difference is all the difference in the world when you’re writing a Silverlight application that you want to be able to maintain and create unit tests for (Yes, I owe a blog post on Test-Driven design, but one glass of grape juice at a time).

MVVMSketch

Core Concept #1:  Separate your User Interface concerns (View) from your Business objects and behaviors (View Model) and from your data/persistence layer (Model).

Core Concept #2 Don’t Look Up.

We tend to conceptualize the View (User Interface objects) at the top, the ViewModel (objects that provide the UI with its data and behaviors) in the middle and the model (often the persistence layer) at the bottom.  The View can know about the ViewModel, the ViewModel about the Model, and the Model, like the cheese, stands alone.

Core Concept #3 – And this is the killer: Binding.

In MVVM the mechanism for the ViewModel to provide data to the View, is for the View to set the ViewModel as its DataContext.  That is so cool; it takes a while to realize the implications.  Further, we don’t just bind data, as I’ll show below.

Why Would You Want To Do That, & What Does It Cost?

The huge advantages of using binding and making the VM the datacontext for the View is that you write less code and, equally important, your behaviors and state are all separated from the UI and thus you have enormously increased the testability of your application. (It is a bear to try to test a UI object because the pesky UI gets in the way. ViewModels have no UI, they have just the things you want to test: “does it behave as expected? and is the data correct at any given instant?”

So, the cost is negative; that is, by adopting MVVM you don’t work harder, you work less, and in exchange for doing less, your code is easier to write, to read, to maintain and to test. Not bad.

Names

Simplifying is one thing, over-simplifying another, and there is an elegance in the chosen names.

The Model is that which the application is modeling. Calling this the database layer or the persistence layer loses site of the fact that the  model might be virtually any time of information in virtually any format.

Calling the top layer the View, rather than the User Interface is important both to emphasize that it is just one of many possible views of the model, and to keep clear that the User Interface comprises both the appearance and the behaviors and the View is concerned only with the appearance.

The ViewModel is the bridge between the Model and the View; and the ViewModel thus owns responsibility for binding the relevant data to the view and for handling user actions appropriately, whether the response is in the widget, elsewhere in the View or in other parts of the application.

A Practical Example

To see this at work, we’ll start by creating a new Silverlight Application. (Complete source code is available here)

Immediately add a new UserControl and name it PeopleView. Here is the Xaml for the UserControl:

01 <UserControl
02 x:Class="MVVMWithBehaviors.PeopleView"
03 xmlns=
04 "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
05 xmlns:x=
06 "http://schemas.microsoft.com/winfx/2006/xaml"
07 xmlns:d=
08 "http://schemas.microsoft.com/expression/blend/2008"
09 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
10 mc:Ignorable="d"
11 d:DesignHeight="300"
12 d:DesignWidth="400">
13 <Grid
14 x:Name="LayoutRoot"
15 Background="White">
16 <ListBox
17 Name="Names"
18 Background="Beige"
19 Width="200"
20 Height="250"
21 HorizontalAlignment="Center"
22 VerticalAlignment="Center"></ListBox>
23 </Grid>
24 </UserControl>
For completeness, here is the Xaml for MainPage.xaml
01 <UserControl
02 x:Class="MVVMWithBehaviors.MainPage"
03 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
04 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
05 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
06 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
07 mc:Ignorable="d"
08 xmlns:me="clr-namespace:MVVMWithBehaviors"
09 d:DesignHeight="300"
10 d:DesignWidth="400">
11 <Grid
12 x:Name="LayoutRoot"
13 Background="White">
14 <me:PeopleView
15 HorizontalAlignment="Stretch"
16 VerticalAlignment="Stretch" />
17 </Grid>
18 </UserControl>
Note: If my solution were named HVP I’d have the following projects to support this model:HVPHVP.Web

HVP.Model

HVP.ViewModel

HVP.View

HVP.Tests

The advantage, for me, is that when I wish to touch a method or property in another class, the compiler will let me know if I’m crossing a project boundary (I’ll need a using statement) and that is a great time to double check that I have my visibility correct (e.g., a class in the View project can include ViewModel but not vice versa)

Next we’ll create PeopleViewModel, as a class.  The job of this class is to expose the properties (and as you’ll see, the methods) that we want the View to bind to.  Specifically, we want the ListBox within the view to bind its ItemsSource property to a collection of People, and we want the Person object to have a property which will display the name of that person. The complete source code is shown here:

C#

01 using System.Collections.ObjectModel;
02 using System.ComponentModel;
03
04 namespace MVVMWithBehaviors
05 {
06 public class PeopleViewModel : INotifyPropertyChanged
07 {
08 public class Person
09 {
10 public string Name { get; private set; }
11 public Person( string name )
12 {
13 this.Name = name;
14 }
15 }
16
17 private ObservableCollection<PERSON> people;
18 public ObservableCollection</PERSON><PERSON> People
19 {
20 get { return people; }
21 set { people = value; }
22 }
23
24 public PeopleViewModel()
25 {
26 MockGetDataFromTheModel();
27 }
28
29 private void MockGetDataFromTheModel()
30 {
31
32 string[ ] firsts = new[ ] { "Tom", "Dick", "Harry", "Joe", "John", "Ringo" };
33 string[ ] lasts = new[ ] { "Liberty", "Papa", "Hanselman", "Heuer", "Brown", "Gu" };
34
35 var r = new System.Random();
36 people = new ObservableCollection </PERSON><PERSON>();
37 for (int i = 0; i  < 10; i++)
38 {
39 people.Add(
40 new Person(
41 firsts[r.Next( firsts.Length )]
42 + " "
43 + lasts[r.Next( lasts.Length )] ) );
44 }
45 }
46
47 public event PropertyChangedEventHandler PropertyChanged;
48 private void OnPropertyChanged( string propertyName )
49 {
50 if (PropertyChanged != null)
51 {
52 PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
53 }
54 }
55 }
56 }

VB.Net

01 Imports System.Collections.ObjectModel
02 Imports System.ComponentModel
03
04 Namespace MVVMWithBehaviors
05 Public Class PeopleViewModel
06 Implements INotifyPropertyChanged
07 Public Class Person
08 Private privateName As String
09 Public Property Name() As String
10 Get
11 Return privateName
12 End Get
13 Private Set(ByVal value As String)
14 privateName = value
15 End Set
16 End Property
17 Public Sub New(ByVal name As String)
18 Me.Name = name
19 End Sub
20 End Class
21
22 Private people_Renamed As ObservableCollection(Of Person)
23 Public Property People() As ObservableCollection(Of Person)
24 Get
25 Return people_Renamed
26 End Get
27 Set(ByVal value As ObservableCollection(Of Person))
28 people_Renamed = value
29 End Set
30 End Property
31
32 Public Sub New()
33 MockGetDataFromTheModel()
34 End Sub
35
36 Private Sub MockGetDataFromTheModel()
37
38 Dim firsts() As String = { "Tom", "Dick", "Harry", "Joe", "John", "Ringo" }
39 Dim lasts() As String = { "Liberty", "Papa", "Hanselman", "Heuer", "Brown", "Gu" }
40
41 Dim r = New System.Random()
42 people_Renamed = New ObservableCollection (Of Person)()
43 For i As Integer = 0 To 9
44 people_Renamed.Add(New Person(firsts(r.Next(firsts.Length)) & " " & lasts(r.Next(lasts.Length))))
45 Next i
46 End Sub
47
48 Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
49 Private Sub OnPropertyChanged(ByVal propertyName As String)
50 RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
51 End Sub
52 End Class

We start by defining a Person (lines 6-15) and then we give the PeopleViewModel class a property People which is an ObservableCollection of Person objects.  The constructor (lines 24-27) calls a method that mocks up getting data from the Model; in this case I just generate ten names on lines 30-48   The final code implements INotifyPropertyChanged, which is not required yet, as the only property we have is an Observable collection.

Binding

We are now ready to bind the ListBox inside the View class to the ViewModel.  Add the following two lines to the ListBox declaration in PeopleView.xaml
ItemsSource="{Binding People}"DisplayMemberPath="Name"

and then add this to the constructor in the code behind:

C#

1 DataContext = new PeopleViewModel();

VB.Net

1 DataContext = New PeopleViewModel()
Running the application will now display the data from the ViewModel in the View

Behavior

The design of the Silverlight HVP says that when an object changes its state (e.g., the user changes the current item in a list box) the View object will notify the state object of the change. The State object then raises the StateChanged event to which all the View objects have subscribed, and each resets its state.
It would be nice to avoid having code in the View to manage the State Change notification; we’d like to bind this as well as the data, thus increasing the overall testability of the project.  Unfortunately, as of now, there is little support for this built into Silverlight (though there is some, using ICommand, with ButtonBase and HyperLink derived classes)
The solution is to be friends with John Papa, who pointed me to the Expression Blend Samples project on CodePlex, which, when installed, provides a library that includes, among other things, the wondrous CallDataMethod, enabling you to trigger a method in your ViewModel based on an event in your view(!)
Since I had to spend quite a bit of time figuring out how to make this work, I thought I’d walk through it here. It is very easy, once you know how, but the project doesn’t yet provide the necessary instructions. Begin by going to the Expression Blend Samples page and downloading the latest release (which currently is from July 12, 2009 and marked Alpha.  This will put a .msi file on your disk, and running that will install the samples; unfortunately it will do so shockingly quietly, and you’ll have no idea what to do next.
Here’s what you do:  in your project you’ll need to add two references. The first is to System.Windows.Interactivity which on my machine is in:
c:\Program Files (x86)\Microsoft SDKs\Expression\Blend Preview for
.NET 4\Interactivity\Libraries\Silverlight\
System.Windows.Interactivity.dll
the second is Expression.Samples.Interactivey, which on my machine was in:
C:\Program Files (x86)\Microsoft Expression\Blend 3
Samples\Silverlight\Design\Expression.Samples.Interactivity.dll
You’ll now modify the view class to include the namespaces:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=
System.Windows.Interactivity"xmlns:si="clr-namespace:Expression.Samples.Interactivity;assembly=
Expression.Samples.Interactivity"

and finally, you modify the control (the listbox) to add the trigger and behavior

01 <ListBox
02 Name="Names"
03 Background="Beige"
04 Width="200"
05 Height="250"
06 HorizontalAlignment="Center"
07 VerticalAlignment="Center"
08 ItemsSource="{Binding People}"
09 DisplayMemberPath="Name">
10 <i:Interaction.Triggers>
11 <i:EventTrigger
12 EventName="SelectionChanged">
13 <si:CallDataMethod
14 Method="HandleSelectionChanged" />
15 </i:EventTrigger>
16 </i:Interaction.Triggers>
17 </ListBox>

The EventTrigger has a property for the EventName; indicating that this trigger will fire when the event SelectionChanged is raised for the ListBox.  The CallDataMethod has a property Method for the name of the method to invoke. Since the ViewModel class is the data context, you don’t need to indicated which class supplies the method, any more than you need to indicate which class has the property People to which the ListBox’s ItemsSource is binding.

Just add that method to the ViewModel class…

C#

1 public void HandleSelectionChanged(){   System.Windows.MessageBox.Show( "Update the state!" );}

VB.Net

1 Public Sub HandleSelectionChanged()
2 System.Windows.MessageBox.Show("Update the state!")
3 End Sub

… and start your program. When you change the selection, the method you’ve bound to will be called.

In the Silverlight HVP this will allow us to bind the event notification to the SelectionChanged event, further decouples the control from its data and logic. The technical term for this is “good.”

Overall Impact of Refactoring for MVVM

While this  is not an exhaustive understanding of MVVM by any means, with these fundamentals, it became obvious how to break up my code, and I found that there was less of it, and it was more intention-revealing.

In fact, the code-behind for my View classes have no code at all except setting the dataContext; and the ViewModel code is short and extremely readable.

All in all, I find MVVM well worth the small cognitive startup costs; yielding a very natural separation of concerns, and perhaps equally important, exposing far more of the program to unit tests, and thus driving down the overall time to release.

———————————–

* In 1978 cult leader Jim Jones induced 900 followers to commit “revolutionary suicide” by knowingly drinking cyanide-laced grape Flavor Aid. To the chagrin of General Foods, the cultural memory of the event is that they drank Kool Aid and the expression. To drink the Kool Aid has evolved to mean “to embrace without reservations, the ideas of a strong leader”

  • Share/Bookmark

The computer thinks these might be related:
  1. Data Validation And Templating in Silverlight 4
  1. Richard Ebel
    August 4th, 2010 at 09:43 | #1

    Richard Ebel :It works with VS EX 2010 and Silverlight 4 and the following changed PeopleView:


  2. Richard Ebel
    August 4th, 2010 at 09:34 | #2

    It works with VS EX 2010 and Silverlight 4 and the following changed PeopleView:


  3. Jason Quinn
    June 15th, 2010 at 05:43 | #3

    I’ve fixed the code sample so it works now with visual studio 2010 and Expression Blend 4. It can be found at http://cid-136dba83ff6950a3.office.live.com/browse.aspx/Public/Code%20Samples

  4. May 25th, 2010 at 16:41 | #4

    @Per H
    Thanks for taking the time to post this after working it out. Your comment was cut off, if you get a chance to fill in the details, that will be terrific.

  5. mark
    May 22nd, 2010 at 19:47 | #5

    Download code doesn’t build. It’s a well written article code. Thanks for the effort. I’ll see if I can get it to compile.

  6. Bryon
    May 21st, 2010 at 15:44 | #6

    @Per H , where are these libraries found? I’m using VS 2010 and Expression Blend 4.

  7. DelC
    May 19th, 2010 at 08:04 | #7

    @Jesse Liberty

    That would be Kool ;-) I’ll try and see if I can get something done in the next week. If I don’t then I’ll fess up to being lazy and leave it for you to take it on. Cheers.

  8. DelC
    May 13th, 2010 at 06:48 | #8

    Hi Jesse,

    Good post, particularly on how simply you can use the Blend Samples to extend the commanding.

    I know you weren’t trying to write the definitive guide to MVVM but it would be good to have a little more on the View Model/Model relationship as mocking up the data within the VM avoids that somewhat.

    We’ve been on the MVVM kool aid since last year and it’s definitely the way to go, although sometimes I think the MVVM police might be about to storm in.

    Some of the team got to see you on your UK visit – thanks again for that.

    • May 16th, 2010 at 10:45 | #9

      I agree, and if you would like to write something and have me chime in and send it back and once done publish here with joint authorship, that would be a gas. If not, it is definitely on my follow-up list. :-)

  9. May 10th, 2010 at 09:55 | #10

    Exactically!

    @Jeff Ballard

    Jeff Ballard :

    Am I correct in stating that the part with the codeplex expression samples and interactivity is basically a way to implement commanding for non button and hyperlink base controls in MVVM?

  10. May 10th, 2010 at 09:53 | #11

    @Ken Byrd
    The problem is that I didn’t explain what I wanted to do, and so you are totally right wrt what i wrote, but not what i meant

    What I was trying to show was an example where a change in the state causes you to want to invoke a method (not just update the view).

  11. May 10th, 2010 at 08:46 | #12

    Jesse,

    Are you breaking any MVVM rule when calling System.Windows.MessageBox.Show in the ViewModel?

    Regards,

    • May 10th, 2010 at 09:44 | #13

      Yes, calling messagebox.show from the vm would be a temporary hack until you move the ui to the view.

  12. Ken Byrd
    May 10th, 2010 at 08:33 | #14

    Why would this method be preferable to simply implementing a SelectedPerson property on the ViewModel?

    {ListBox ItemsSource=”{Binding People}”
    SelectedItem=”{Binding SelectedPerson, Mode=TwoWay}” />

    Within your ViewModel, you could simply watch for changes to the SelectedPerson property which wouldn’t require 3rd party codeplex code!

  13. May 9th, 2010 at 12:06 | #15

    Hi. This is a great example, and I agree that one has to apply a little KISS to MVVM in order to get your brain around it! However, using VS2010RTM and Blend4 beta, I think the following needs to be changed?

    1) I updated the references and the XAML:

    xmlns:si=”http://schemas.microsoft.com/expression/2010/interactivity”
    xmlns:sa=”http://schemas.microsoft.com/expression/2010/interactions”

    2) and changed the CallDataMethod to CallMethodAction like this:

  14. JasonBSteele
    May 9th, 2010 at 07:46 | #16

    And I thought references to drinking Kool Aid were more to do with Kool Aid Acid Test… which is more to do with seeing things that aren’t there! ;)

  15. May 9th, 2010 at 01:55 | #17

    Heh ;) Hi Jesse I like it very much your intro in this post . Trend’s killing our precious time.

  16. Jeff Ballard
    May 8th, 2010 at 19:20 | #18

    Jesse,

    Am I correct in stating that the part with the codeplex expression samples and interactivity is basically a way to implement commanding for non button and hyperlink base controls in MVVM? I was trying to do something similar using Prism and was having trouble getting it to work although I did have only a few minutes to troueshoot before I had to leave for a family event. :)

    Great article!

  1. June 8th, 2010 at 09:01 | #1
  2. June 9th, 2010 at 18:37 | #2