The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








Latest Diggs - Programming

Internet Blogs - Blog Top Sites

Site Hits

Total: 2,639,104
since: 19 Jan 2005

Data Binding in WPF with the Monostate Pattern

posted Mon 13 Nov 06

Quite often what happens to me is that I will be using what I think of as a "trick" or a "really cool way of doing things" only to find out months later that what I was doing actually has a name. For example, I once went through an entire conception-to-production life cycle of an ASP.NET application where I enforced model-view-presenter constraints on code separation and yet I didn't know that people already had coined the MVP and MVC patterns and given them names and even published them in books!

So I've been toying with WPF data binding a lot lately, mostly because many of the samples you see for data binding (with the exception of some awesome blogs like Pavan Podila's or Bea Costa's) are naive and have no real value in a real-world application. Writing a class where the constructor is responsible for pre-loading the items in a collection to which the GUI will bind is neither scalable nor useful. What you need is a way for WPF to create an instance of the model object declaratively via the ObjectDataProvider tag and a way for your code to access that data to manipulate it without violating the boundaries of model/view/controller. In other words, to keep the MVC boundaries clean, your code-behind cannot ask the VIEW for a reference to the MODEL. Many samples cheat by grabbing the object data provider using the Resources dictionary from a code-behind - this is a flat-out violation of MVC and simply not good enough for me.

This is when I stumbled on Monostate. I'd used the pattern before, but I finally found a book that gave it a name - Agile Principles, Patterns, and Practices in C# by Robert C Martin and Micah Martin. Monostate is a really simple concept - you can instantiate an infinite number of objects, but all publicly accessible properties refer to the same set of data. In other words, the private members are static and the public members are not. What this enables you to do is allow WPF to create its own private instance of your model object ( you are using model objects, aren't you?? ) and you can create your own instance of the model object from your controller/presenter. Changes made by the controller/presenter are then automatically reflected in the GUI because your model objects are either classes that implement INotifyPropertyChanged or they are ObservableCollections of classes that implement INotifyPropertyChanged.

Take the following code, which provides for a Customer class with a FirstName and LastName property. There is also an ObservableCollection<Customer> that can be used as a binding source for list-type items in XAML:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace MonostateDemo.Model
{
public class Customer : INotifyPropertyChanged
{
    private string _firstName;
    private string _lastName;
    public Customer()
    {
    }

 
   public Customer(string firstName, string lastName)
    {
        _firstName = firstName;
        _lastName = lastName;
    }
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; NotifyChanged("FirstName"); }
    }
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; NotifyChanged("LastName");  }
    }
    private void NotifyChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion
}







public class CustomerList : ObservableCollection<Customer>
{
    public CustomerList()
    {
    }
}
}

With this class in place, you can create a resource dictionary that contains a data template that will bind to a new class I called ModelRoot, which basically just exposed public monostate properties, one of which is called Customers, which is an auto-instantiated object of type CustomerList. The following is the code for the resource dictionary DataTemplates.xaml:

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:model="clr-namespace:MonostateDemo.Model;assembly=MonostateDemo.Model"
    >
  <ObjectDataProvider x:Key="DataModel" ObjectType="{x:Type model:ModelRoot}"/>
  <DataTemplate x:Key="customerTemplate">
    <StackPanel>
      <TextBlock Text="{Binding FirstName}"/>
      <TextBlock Text="{Binding LastName}"/>
    </StackPanel>   
  </DataTemplate>
</ResourceDictionary>

You may notice that the ModelRoot class is actually contained in an Assembly outside the main application Assembly. You are separating your model from the application's executable Assembly, aren't you? :) So, with a data template in place that can be used to render individual customers, all we have to do now is create a list box that uses the object provider as the items source and customerTemplate as the items template:

 <Window x:Class="MonostateBindingDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
    Title="MonostateBindingDemo" Height="300" Width="300"
    >
  <Window.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="DataTemplates.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
       
  </Window.Resources>
  <StackPanel>
    <ListBox ItemsSource="{Binding Path=Customers, Source={StaticResource DataModel}}"
        ItemTemplate="{StaticResource customerTemplate}"/>
  </StackPanel>
</Window>

At this point, you've got a list box that is bound to an instance of ModelRoot, specifically to the Customers property of ModelRoot. You can then use your own code to create your own instance of ModelRoot and manipulate the Customers property - and your changes will be automatically reflected in the GUI. Because Customer implements INotifyPropertyChanged, the WPF GUI will actually recognize when changes take place to individual customers as well as when customers are added to or removed from the collection. Here's the code for my Window1.xaml.cs that sets up a couple fake customers and sets up a timer that changes the first customer's last name to the current time, just so you can watch the change take place in the GUI:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using MonostateDemo.Model;
using System.Timers;

namespace MonostateBindingDemo
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : System.Windows.Window
{
    public Window1()
    {
        InitializeComponent();
        ModelRoot root = new ModelRoot();
        root.Customers.Add(new Customer("Kevin", "Hoffman"));
        root.Customers.Add(new Customer("Bob", "Johnson"));
        Timer t = new Timer(3000);
        t.Elapsed += new ElapsedEventHandler(t_Elapsed);
        t.Start();
    }
    void t_Elapsed(object sender, ElapsedEventArgs e)
    {
        ModelRoot root = new ModelRoot();
        root.Customers[0].LastName = DateTime.Now.ToLongTimeString();
    }
}
}

I encourage you to copy this code, create your own application and run it. Then, experiment with adding more and more real-world functionality to it. Make a button that clears the list of customers and re-loads them from a database. This is a fantastic way of binding to data in a WPF application and one that, in my opinion, matches really well with real-world application development needs - but you may need to kick the tires on it to prove it to yourself.

tags:            

links: digg this    del.icio.us    technorati    reddit




1. Rob left...

Nice work! Looks like it's time to refactor some of my code :)


2. Rob L left...
Tue 16 Jan 07 5:01 pm

I am new to the WPF,can you show the code for the ModelRoot class. I realize that it is in a different assembly.


3. kaleem left...
Mon 12 Feb 07 7:00 am

Hey sir, i think your complicating this thing by not explaining in detail what is ModelRoot class, i dont think we the beginners can get into it without the code or a thorough explanation, plzz


4. Kevin Hoffman left...

ModelRoot is a class that I created that contains properties that point to the rest of my model. They are _instance_ properties that point to _static_ member variables, which is the essential core of the Monostate pattern.

This allows me to create an infinite number of instances of the ModelRoot class, from any number of varied entry points, and still be assured that I am accessing the same set of data.


5. Rob L left...
Wed 28 Feb 07 10:45 am

This was the ModelRoot class that I came up with. Worked fine with Kevin's code. Nice job Kevin, it's working out really well for us. A few issues with the View and referencing of external assemblies. I have seen them documented as future fixes for Orca.

namespace MonostateDemo.Model {

  • public class ModelRoot

  • {

    • public ModelRoot()

    • {

    • }

    • private static CustomerList _customerList = new CustomerList();

  • public CustomerList Customers

  • {

    • get

    • {

      • return _customerList;

    • }

  • }

  • }

  • //Some classes to show the difference between Monostate and Singleton

  • //Simple Monostate class

  • public class Monostate

  • {

    • private static int num_;

  • public int Num_

  • {

    • get

    • {

      • return num_;

    • }

    • set

    • {

      • num_ = value;

    • }

  • }

  • }

  • //Simple Singleton class

  • public class Singleton

  • {

    • private static Singleton instance;

  • private Singleton() { }

  • public static Singleton Instance

  • {

    • get

    • {

      • if (instance == null)

      • {

        • instance = new Singleton();

      • }

      • return instance;

    • }

  • }

  • }

}


Tag Related Posts

CLINQ v1 Demo - Network Message Filtering

Wed 09 Jan 08 7:47 P GMT-05
tags:        

Building a Ledger Style for WPF Grids

Tue 21 Aug 07 3:30 P GMT-05
tags:    

My first "Acropolis" Application

Mon 04 Jun 07 1:40 P GMT-05
tags:      

Exploring the Delegate Design Pattern

Mon 14 May 07 6:30 P GMT-05

Will Silverlight be DOA?

Mon 16 Apr 07 8:02 P GMT-05

Exploring the MVC Pattern in WPF

Tue 10 Apr 07 12:51 P GMT-05
tags:                      

WPF Bindings == WTF Bindings?

Mon 12 Mar 07 6:31 P GMT-05

On MUDs

Thu 08 Mar 07 5:00 A GMT-05
tags:                    

Cocoa Programming vs. WPF : NIB vs XAML

Tue 20 Feb 07 2:09 P GMT-05

Cocoa Bindings vs. WPF Binding

Thu 15 Feb 07 5:41 P GMT-05
tags:                

Ulysses Agenda Makes Redmond Developer News

Wed 29 Nov 06 7:10 P GMT-05
tags:                

Ulysses Agenda - Network Engine Test 1

Mon 09 Oct 06 2:26 A GMT-05
tags:              

Ulysses Agenda : First Cut Networking Design

Thu 14 Sep 06 12:46 A GMT-05
tags:                  

First Impressions of Windows Vista RC1

Thu 07 Sep 06 1:30 P GMT-05
tags:                      

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

WPF Slide Show and Photo Album

Fri 18 Aug 06 6:48 P GMT-05

ADO.NET Entity Framework Announced Today!

Wed 16 Aug 06 11:08 A GMT-05

.NET Framework 3.0 June CTP is out!

Fri 23 Jun 06 6:23 P GMT-05
tags:                

Tech-Ed 2006 - Session Reviews

Tue 13 Jun 06 6:22 P GMT-05
tags:                    

Tech-Ed 2006 Day 1 - Registration Day

Sun 11 Jun 06 7:17 P GMT-05

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags: