A few folks asked me to provide a ViewModel sample of some sort.  I thought this was a great idea, since I don’t know that I had seen a straight-forward ViewModel sample yet.  So here it is: HelloWorld.ViewModel!

 Click to launch Hello World ViewModel in Silverlight
Click the image to view the Silverlight sample live.

Let’s start out by looking at the code for the ViewModel class, since that’s the file that I authored first.

   1: using System;
   2: using System.ComponentModel;
   3:  
   4: namespace HelloWorldViewModel
   5: {
   6:     public class HelloWorldModel : INotifyPropertyChanged
   7:     {
   8:         private string _name;
   9:         private bool _isHavingGoodDay = true;
  10:  
  11:         /// <summary>
  12:         /// The user's name
  13:         /// </summary>
  14:         public string Name
  15:         {
  16:             get { return this._name; }
  17:             set
  18:             {
  19:                 if (this._name != value)
  20:                 {
  21:                     this._name = value;
  22:                     this.RaisePropertyChanged("Name");
  23:                     this.RaisePropertyChanged("Greeting");
  24:                 }
  25:             }
  26:         }
  27:  
  28:         /// <summary>
  29:         /// Whether or not the user is having a good day
  30:         /// </summary>
  31:         public bool IsHavingGoodDay
  32:         {
  33:             get { return this._isHavingGoodDay; }
  34:             set
  35:             {
  36:                 if (this._isHavingGoodDay != value)
  37:                 {
  38:                     this._isHavingGoodDay = value;
  39:                     this.RaisePropertyChanged("IsHavingGoodDay");
  40:                     this.RaisePropertyChanged("Greeting");
  41:                 }
  42:             }
  43:         }
  44:  
  45:         /// <summary>
  46:         /// A greeting for the user
  47:         /// </summary>
  48:         public string Greeting
  49:         {
  50:             get
  51:             {
  52:                 if (!string.IsNullOrEmpty(this.Name))
  53:                 {
  54:                     if (this.IsHavingGoodDay)
  55:                     {
  56:                         return string.Format("Awesome; glad to see you {0}", this.Name);
  57:                     }
  58:  
  59:                     return string.Format("Sorry to hear that, {0}.  I hope things turn around.", this.Name);
  60:                 }
  61:  
  62:                 return "Hello World!";
  63:             }
  64:         }
  65:  
  66:         /// <summary>
  67:         /// Support Binding
  68:         /// </summary>
  69:         public event PropertyChangedEventHandler PropertyChanged;
  70:  
  71:         /// <summary>
  72:         /// Helper method for raising the PropertyChanged event
  73:         /// </summary>
  74:         /// <param name="propertyName"></param>
  75:         private void RaisePropertyChanged(string propertyName)
  76:         {
  77:             if (this.PropertyChanged != null)
  78:             {
  79:                 this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  80:             }
  81:         }
  82:     }
  83: }

The takeaways from this class:

  1. It’s a POCO
  2. It implements System.ComponentModel.INotifyPropertyChanged so that we can bind to its properties
  3. That’s it
  4. Oh yeah, no UI knowledge – That’s important!

Now for the other side of the coin, the View.

   1: <UserControl x:Class="HelloWorldViewModel.Page"
   2:              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:              xmlns:app="clr-namespace:HelloWorldViewModel">
   5:     <UserControl.Resources>
   6:         <app:VisibilityConverter x:Key="VisibilityConverter" />
   7:     </UserControl.Resources>
   8:     <UserControl.DataContext>
   9:         <app:HelloWorldModel />
  10:     </UserControl.DataContext>
  11:     <Grid x:Name="LayoutRoot" Background="Black">
  12:         <Image Source="Smiley.jpg"
  13:                HorizontalAlignment="Stretch"
  14:                VerticalAlignment="Stretch"
  15:                Visibility="{Binding IsHavingGoodDay, Converter={StaticResource VisibilityConverter}}" />
  16:         <Image Source="Sad.jpg"
  17:                HorizontalAlignment="Stretch"
  18:                VerticalAlignment="Stretch"
  19:                Visibility="{Binding IsHavingGoodDay, Converter={StaticResource VisibilityConverter}, ConverterParameter=Collapsed}" />
  20:         <Border Width="800"
  21:                 HorizontalAlignment="Center"
  22:                 VerticalAlignment="Top"
  23:                 CornerRadius="0,0,125,125"
  24:                 Background="#AABEBEFF">
  25:             <TextBlock Grid.Row="3"
  26:                        Text="{Binding Greeting}"
  27:                        HorizontalAlignment="Center"
  28:                        FontSize="24" />
  29:         </Border>
  30:         <Border Width="500"
  31:                 HorizontalAlignment="Center"
  32:                 VerticalAlignment="Bottom"
  33:                 CornerRadius="125,125,0,0"
  34:                 Background="#AABEBEFF">
  35:             <Grid Width="300"
  36:                   VerticalAlignment="Top"
  37:                   HorizontalAlignment="Center"
  38:                   Margin="10,20,10,0">
  39:                 <Grid.RowDefinitions>
  40:                     <RowDefinition />
  41:                     <RowDefinition />
  42:                     <RowDefinition />
  43:                 </Grid.RowDefinitions>
  44:                 
  45:                 <TextBlock Grid.Row="0" Text="Enter your name:" />
  46:                 <TextBox Grid.Row="1" Text="{Binding Path=Name, Mode=TwoWay}" />
  47:                 
  48:                 <CheckBox Grid.Row="2"
  49:                           Content="I'm having a good day"
  50:                           IsChecked="{Binding Path=IsHavingGoodDay, Mode=TwoWay}" />
  51:             </Grid>
  52:         </Border>
  53:     </Grid>
  54: </UserControl>


What the View exhibits:

  1. Instantiates a VisibilityConverter for later use
  2. Instantiates the ViewModel declaratively, using the <app:HelloWorldModel /> tag; and assigns this ViewModel instance to be the DataContext of the UserControl (and all child controls)
  3. Declares 2 images, Smiley.jpg and Sad.jpg, and binds their Visibility properties to the IsHavingGoodDay property on the ViewModel.  Notice the VisibilityConverter use and the ConverterParameter.  This allows a single boolean to drive 2 different controls, with opposite behavior.  The VisibilityConverter is a custom IValueConverter I wrote.  I’ll do a post on it later.
  4. Binds a TextBlock to the Greeting property on the ViewModel.
  5. Binds the textbox and the checkbox to the ViewModel using TwoWay binding.

Now, let’s look at the code-behind for the View.  This is by far the most important part of this sample.

   1: using System;
   2: using System.Windows.Controls;
   3:  
   4: namespace HelloWorldViewModel
   5: {
   6:     public partial class Page : UserControl
   7:     {
   8:         public Page()
   9:         {
  10:             InitializeComponent();
  11:         }
  12:     }
  13: }


Yep, (essentially) no code in the code-behind.  And yes, that is the most important part of the ViewModel pattern.  You can have your View bound to your ViewModel using 1-way and 2-way binding, with logic in your ViewModel and not a lick of logic in your View’s code-behind.

As I mentioned in my ViewModel Pattern introductory post, it’s important to disallow any view-specific behavior from leaking into the ViewModel.  The visibility of the two images in this sample are perfect examples of this point.  The ViewModel exposes a boolean, not a Visibility property.  The View can then do whatever it wants with that boolean.  For all the ViewModel knows, the View doesn’t do anything with it, but in this case, there are 2 images that are toggled based on the value.

In future posts, I’ll talk about more ViewModel details that go beyond Hello World type applications.  Most notably, I’ll be writing about service references and how a ViewModel should get data from services to be exposed to the View.  Keep in mind that this pattern can be applied in either WPF or Silverlight.

You can download the source code for this application here.