The power of WPF binding really shines when you use design time data to have a live preview of the aspect of your UI without the need to press F5 to load actual data. Design time data is a cool feature you can have with little effort, suppose you have a simple windows and you want to show a list of customers, taken from the northwind datadabase inside a Listbox, personlizing the DataTemplate.

I start with  simple ViewModelBase, that is really far to be a real Base View Model to implement a full MVVM solution, but it serves me to show how to use design time data without scare people telling them to implement complex patterns or similar stuff.

   1: public abstract class ViewModelBase : MarkupExtension, INotifyPropertyChanged

   2: {

   3:  

   4:     public event PropertyChangedEventHandler PropertyChanged;

   5:  

   6:     protected virtual void OnPropertyChanged(String propertyName)

   7:     {

   8:  

   9:         var temp = PropertyChanged;

  10:         if (temp != null)

  11:         {

  12:             temp(this, new PropertyChangedEventArgs(propertyName));

  13:         }

  14:     }

  15:  

  16:     private DependencyObject syncRoot = new DependencyObject();

  17:  

  18:     protected Boolean IsInDesignMode

  19:     {

  20:         get { return DesignerProperties.GetIsInDesignMode(syncRoot); }

  21:     }

This is really simple base class that implements INotifyPropertyChanged and inherits from MarkupExtension, it has also an IsInDesign mode property to detect if the code is running inside a designer.

   1: protected abstract void CommonInit();

   2:  

   3: protected abstract void RuntimeInit();

   4:  

   5: protected abstract void DesignTimeInit();

   6:  

   7: protected ViewModelBase()

   8: {

   9:     this.CommonInit();

  10:     if (!IsInDesignMode)

  11:     {

  12:         this.RuntimeInit();

  13:     }

  14: }

  15:  

  16: public override object ProvideValue(IServiceProvider serviceProvider)

  17: {

  18:     this.DesignTimeInit();

  19:     return this;

  20: }

Then I defined three abstract methods, the first is called CommonInit() and is used to do common initialization, then the RuntimeInit() is called to do all initialization I do not want to do when the viewmodel is used inside the designer, finally the DesignTimeInit() is called when the object is constructed inside the Designer. The trick is that the constructor call the RuntimeInit() only when we are outside the designer and the DesignTimeInit() is simply called inside the ProvideValue() virtual method of the base MarkupExtension class

Then I create a MainWindowViewModel inheriting from this class, add an ObservableCollection<Customers> to show data and implemented the initialization methods, the RuntimeInit() loads data from database.

   1: protected override void RuntimeInit()

   2:  {

   3:      using (NorthWind context = new NorthWind())

   4:      {

   5:          foreach (var customer in context.Customers)

   6:          {

   7:              LoadedCustomers.Add(customer);

   8:          }

   9:      }

  10:  }

Then in the DesignTimeInit() I create some fake objects that will be used by the designer, you can do it simple using Fizzware NBuilder library.

   1: protected override void DesignTimeInit()

   2: {

   3:     for (int i = 0; i < 10; i++)

   4:     {

   5:         Customers customerDummy = FizzWare.NBuilder.Builder<Customers>.CreateNew().Build();

   6:         LoadedCustomers.Add(customerDummy);

   7:     }

   8: }

Now I fire blend and open the solution, create a windows then add the design time data context to the first Grid control

   1: <Grid d:DataContext="{sampleproject:MainWindowViewModel}">

This will call the ProvideValue of the MarkupExtension class, so the object will be constructed with some dummy design data, then I drop a ListBox inside the window and bind its ItemsSource property with designer

image

Figure 1: Bind with designer

The cool part is that the designer correctly recognize the ViewModel inside the DataContext and shows me the list of properties that can be bound to the ItemsControl property. Now I right click the ListBox and ask blend to edit the ItemTemplate, then create a simple layout with a border and a 2×2 grid.

image

Figure 2: The layout for the DataTemplate of the ListBox

Now that I created the grid with four cells, I need to bind the label of the second column to the right properties of the Customers object, so I simply select the label, then ask to DataBind the Content:

image

Figure 3: Thanks to Design Time Data, blend designer can use reflection to understand the properties of the Customers Object, so we can easily choose the property to bind

The cool part is that the interface in the designer immediately reflects the result with the Design Time Data

image

Figure 4: Designer uses design time data to render the interface directly inside the designer

This is a killer feature because permits you to have a real look at how the UI will be rendered with data.

Code sample is here.

Gian Maria

Tags: ,