Colin Eberhardt's Technology Adventures

ViewModel INotifyPropertyChanged Code Generation

April 21st, 2011

This blog post describes a novel method of generating boiler-plate MVVM code using codesnippet automation. You simply add attributes to your view model classes and the code is generated for you!

Model-View-ViewModel (MVVM) has become the de facto pattern for Silverlight, WPF and WP7 applications, providing code that is easily tested and couples cleanly to the view via databinding. However, one small problem with MVVM is that it relies on the INotifyPropertyChanged (INPC) interface and the boiler-plate code which this entails.

This blog post describes a technique for implementing INPC and adding properties to your view model as easily as this:

[SnippetINotifyPropertyChanged]
[SnippetPropertyINPC(field = "_surname", type = "string", property = "Surname")]
[SnippetPropertyINPC(field = "_forename", type = "string", property = "Forename")]
public partial class PersonViewModel : INotifyPropertyChanged
{
}

There are hundreds of blog posts that describe solutions to the problem of implementing INPC including simple options like a base-class that implements the INPC interface, the popular approach of using lambda expressions and more complex solutions involving Intermediate Language Weaving (AOP), or dynamic proxies. However, for the sake of simplicity, most of the projects I have worked on have opted for a manual approach – with individual developers using codesnippets if they so wish.

There are a couple of problems with codesnippets, firstly they are not refactor friendly, secondly they do not reduce boiler-plate code, they simply provide a method for adding this code more quickly!

Yesterday I published an article on codeproject which describes a technique for ‘automating’ code snippets, where you indicate the use of a codesnippet declaratively via an attribute, with the resultant code being generated in a partial class. Here I am going to show how it can be used to streamline the creation of ViewModels and results in the removal of boiler-plate code.

The first step to using this technique is to add the CodeGen folder to your project. This folder includes a number of T4 templates (Visual Studio’s built in code-generation framework):

With these templates added to your project, if you add a codesnippet to the project (i.e. a .snippet file), a corresponding attribute will be generated when the T4 templates are run. You can see in the above screenshot that a couple of snippets have been added and attributes generated.

The T4 templates are run when the project is built, or can be run on-demand by clicking the button indicated below:

So let’s have a go at generating our view model code …

We’ll create a simple Person view model, which has properties of Surname, Forename and a dependent property of FullName which concatenates the two together. We’ll start by adding the INPC implementation to our class via an automated snippet:

[SnippetINotifyPropertyChanged]
public partial class PersonViewModel : INotifyPropertyChanged
{
}

By adding the attribute above and compiling the code, you will find that a generated counterpart to our view model is created:

This file contains the code defined in our INPC codesnippet:

using System.ComponentModel;
 
namespace ViewModelCodeGeneration
{
  public partial class PersonViewModel
  {
 
    #region INotifyPropertyChanged Members
 
    /// <summary>
    /// Occurs when a property changes
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
 
    /// <summary>
    /// Raises a PropertyChanged event
    /// </summary>
    protected void OnPropertyChanged(string property)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(property));
      }
    }
 
    #endregion
  }
}

We can now add a property to our view model:

[SnippetINotifyPropertyChanged]
[SnippetPropertyINPC(field = "_surname", type = "string", property = "Surname")]
public partial class PersonViewModel : INotifyPropertyChanged
{
}

Compiling the code and inspecting the generated file, we can see that the code has been generated based on the codesnippet that adds a property (with INPC PropertyChanged), based on the attribute parameters supplied above:

using System.ComponentModel;
 
namespace ViewModelCodeGeneration
{
  public partial class PersonViewModel
  {
 
    #region INotifyPropertyChanged Members
 
    /// <summary>
    /// Occurs when a property changes
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
 
    /// <summary>
    /// Raises a PropertyChanged event
    /// </summary>
    protected void OnPropertyChanged(string property)
    {
      if (PropertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(property));
      }
    }
 
    #endregion
 
 
    /// <summary>
    /// Field which backs the Surname property
    /// </summary>
    private string _surname = null;
 
    public static readonly string SurnameProperty = "Surname";
 
    /// <summary>
    /// Gets / sets the Surname value
    /// </summary>
    public string Surname
    {
      get { return _surname; }
      set
      {
        if (_surname == value)
          return;
 
        _surname = value;
 
        OnSurnameChanged(value);
 
        OnPropertyChanged(SurnameProperty);
      }
    }
 
    /// <summary>
    /// Invoked when the value of Surname changes
    /// </summary>
    partial void OnSurnameChanged(string value);
  }
}

Finally, we add the second property, and add implementations for the partial methods that are invoked when either Surname or Forename changes, allowing us to implement FullName:

[SnippetINotifyPropertyChanged]
[SnippetPropertyINPC(field = "_surname", type = "string", property = "Surname")]
[SnippetPropertyINPC(field = "_forename", type = "string", property = "Forename")]
public partial class PersonViewModel : INotifyPropertyChanged
{
  public static readonly string FullNameProperty = "FullName";
 
  partial void OnForenameChanged(string value)
  {
    OnPropertyChanged(FullNameProperty);
  }
 
  partial void OnSurnameChanged(string value)
  {
    OnPropertyChanged(FullNameProperty);
  }
 
  public string FullName
  {
    get
    {
      return Surname + ", " + Forename;
    }
  }
}

All that’s left to do is bind our view model to the view:

<Border BorderBrush="DarkGray" BorderThickness="4"
        CornerRadius="3"
        VerticalAlignment="Center">
  <Grid l:GridUtils.ColumnDefinitions="*,*"
          l:GridUtils.RowDefinitions="Auto,Auto,">
 
    <TextBlock Text="{Binding FullName}" FontWeight="Bold"
                Grid.ColumnSpan="2"/>
 
    <TextBlock Text="Surname:"
                Grid.Row="1"/>
    <TextBox Text="{Binding Surname, Mode=TwoWay}"
              Grid.Column="1" Grid.Row="1"/>  
 
    <TextBlock Text="Forename:"
                Grid.Row="2"/>
    <TextBox Text="{Binding Forename, Mode=TwoWay}"
              Grid.Column="1" Grid.Row="2"/>
 
  </Grid>
</Border>

(Note the simplified grid markup!)

Here’s the code for this very simple example in action:

This blog post has described a method for generating the boiler-plate code that the MVVM patterns requires. The use of T4 templates and partial classes mirrors the way that the Visual Studio designer generates code. Personally I think the end result is much easier to understand that the dynamic proxy or aspects / weaving approach described by others. The example given in this blog post is pretty trivial, but when you use it for bigger projects with complex view-models containing numerous properties, you really start to feel the benefit.

Furthermore, the technique described here can be used to automate any codesnippet! you can use it to generate dependency properties for example.

Enjoy!

You can download the sourcecode here: ViewModelGeneration.zip

For more information regarding how T4 / Env.DTE / XSLT are used to automate your codesnippets I would encourage you to read my codeproject article.

Regards, Colin E.

A Fast Loading Windows Phone 7 NavigationList Control

April 18th, 2011

This blog post describes a Windows Phone 7 NavigationList control, a list control designed for navigation pages. The NavigationList renders twice as fast as a ListBox and has a slightly simpler API.

A few months ago I blogged about the relative performance of the Windows Phone 7 emulator versus the same code being run on the real hardware. There were a couple of take-home messages from this blog post, firstly the performance on real hardware is typically much slower than the emulator, and secondly an ItemsControl can render the same content as a ListBox in less time, making them a better choice for rendering lists of items for navigation.

The recent NoDo updates included some performance improvements, most of which focus on load performance. I re-ran the tests from my previous blog post pre-NoDo and after installing NoDo on the phone (Samsung Omnia), but saw no difference in performance between my measurements, which is pretty much what I expected:

Load time is still a significant issue for Windows Phone 7 Silverlight applications, and anything that can be done to reduce this will make your application more slick and useable.

I still see examples on the internet of people using the ListBox for navigation within Windows Phone 7 application, despite the poor performance when compared with an ItemsControl. This is probably because ListBox has a slightly simpler API. In order to combat this I have come up with a NavigationList control, which is based on an ItemsControl. This control wraps up all the ItemsControl configuration and click / manipulation handling to give a fast and easy-to-use control which simply raises a Navigation event in response to user interactions.

NavigationList Control

The NavigationList control is a lightweight control that can be used to render a list of items (base on an ItemTemplate). The following XAML snippet shows how to use this control:

<l:NavigationList ItemsSource="{Binding}"
              Navigation="NavigationList_Navigation">
  <l:NavigationList.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding}" FontSize="25"/>
    </DataTemplate>
  </l:NavigationList.ItemTemplate>
</l:NavigationList>

The NavigationList has an ItemsSource property which is used to supply your list of items, and an optional ItemTemplate template where you specify how they are rendered.

The control fires a Navigation event whenever the user clicks on an item. This event has an Item argument which contains the item (from the ItemsSource) that was selected. This is typically used to navigate to a new page, as in the example below:

private void NavigationList_Navigation(object sender, NavigationEventArgs e)
{
  // pass the datacontext to the page we are navigating to via the RootVisual.
  FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
  root.DataContext = e.Item;
  NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.RelativeOrAbsolute));
}

So, how does the NavigationList compare to a ListBox? In terms or performance, it is a clear winner. The example project for this blog post has a test which renders exactly the same content with a ListBox and a NavigationList. Here’s how the load time of the page compares:

A page which uses a NavigationList renders twice as fast as an equivalent page that uses a ListBox!

Another problem with using ListBox is that selection state is ‘persisted’ in the back stack, therefore when you navigate back to the page, you must clear the SelectedItem. Interestingly I just spotted a blog post by a WP7 developer who’s application was rejected during the marketplace submission process for forgetting to do just this!

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
  base.OnNavigatedTo(e);
 
  // reset selection so that the same item can be re-selected
  navigationListBox.SelectedItem = null;      
}
 
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
  if (navigationListBox.SelectedItem == null)
    return;
 
  // pass the datacontext to the page we are navigating to via the RootVisual.
  FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
  root.DataContext = navigationListBox.SelectedItem;
  NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.RelativeOrAbsolute));
}

NavigationList Implementation

The control itself is quite simple, the template includes an ItemsControl, which binds to the NavigationList ItemsSource and ItemTemplate dependency properties. The ItemsControl uses a VirtualizingStackPanel for the ItemsPanel
to give a faster load time (as does the ListBox):

<Style TargetType="l:NavigationList">
  <Setter Property="ItemTemplate">
    <Setter.Value>
      <DataTemplate>
        <TextBlock Text="{Binding}"/>
      </DataTemplate>
    </Setter.Value>
  </Setter>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate>
 
        <l:ItemsControlEx x:Name="itemsControl"
                      ItemsSource="{Binding Path=ItemsSource, RelativeSource={RelativeSource TemplatedParent}}"
                      ItemTemplate="{Binding Path=ItemTemplate, RelativeSource={RelativeSource TemplatedParent}}">                        
          <l:ItemsControlEx.ItemsPanel>
            <ItemsPanelTemplate>
              <VirtualizingStackPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>
          </l:ItemsControlEx.ItemsPanel>
          <l:ItemsControlEx.Template>
            <ControlTemplate>
              <ScrollViewer>
                <ItemsPresenter/>
              </ScrollViewer>
            </ControlTemplate>
          </l:ItemsControlEx.Template>
        </l:ItemsControlEx>
 
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

ItemsControlEx is a simple subclass of ItemsControl which raises an event each time an item is added to the panel:

/// <summary>
/// Extends an ItemsControl, raising an event when the PrepareContainerForItemOverride
/// override is invoked.
/// </summary>
public class ItemsControlEx : ItemsControl
{
  protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
  {
    base.PrepareContainerForItemOverride(element, item);
 
    OnPrepareContainerForItem(new PrepareContainerForItemEventArgs(element, item));
  }
 
  /// <summary>
  /// Occurs when the PrepareContainerForItemOverride method is invoked
  /// </summary>
  public event EventHandler<PrepareContainerForItemEventArgs> PrepareContainerForItem;
 
  /// <summary>
  /// Raises the PrepareContainerForItem event.
  /// </summary>
  protected void OnPrepareContainerForItem(PrepareContainerForItemEventArgs args)
  {
    if (PrepareContainerForItem != null)
    {
      PrepareContainerForItem(this, args);
    }
  }
}
 
/// <summary>
/// Provides data for the PrepareContainerForItem event.
/// </summary>
public class PrepareContainerForItemEventArgs : EventArgs
{
  public PrepareContainerForItemEventArgs(DependencyObject element, object item)
  {
    Element = element;
    Item = item;
  }
 
  public DependencyObject Element { get; private set; }
 
  public object Item { get; private set; }
}

The NavigationControl locates the ItemsControlEx instance from its template to handle this event. Each time an element is added, handlers are added to various events:

public override void OnApplyTemplate()
{
  base.OnApplyTemplate();
 
  var itemsControl = GetTemplateChild("itemsControl") as ItemsControlEx;
  itemsControl.PrepareContainerForItem += ItemsControl_PrepareContainerForItem;
}
 
private void ItemsControl_PrepareContainerForItem(object sender, PrepareContainerForItemEventArgs e)
{
  var element = e.Element as UIElement;
 
  // handle events on the elements added to the ItemsControl
  element.MouseLeftButtonUp += Element_MouseLeftButtonUp;
  element.ManipulationStarted += Element_ManipulationStarted;
  element.ManipulationDelta += Element_ManipulationDelta;
}

The above could have been achieved without the use of ItemsControlEx by providing a container for each item that is added, much the same was as the ListBox contains items within a ListBoxItem instance. However, the aim here is to make the control as lightweight as possible, which means minimizing the number of visual elements created.

The Element_MouseLeftButtonUp event handler raises the Navigation event, but what are the manipulation event handlers for? This is because if the NavigationList is used within a control that performs some action due to manipulation, the Pivot control which reacts to swipe for example, a mouse up event is still fired when the manipulation ends. This results in a navigation firing incorrectly, see Tore Lervik’s blog for more details.

private bool _manipulationDeltaStarted;
 
private void Element_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
  _manipulationDeltaStarted = true;
}
 
private void Element_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
  _manipulationDeltaStarted = false;
}
 
private void Element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
  if (_manipulationDeltaStarted)
    return;
 
  // raises the Navigation event on mouse up, but only if a manipulation delta
  // has not started.            
  var element = sender as FrameworkElement;
  OnNavigation(new NavigationEventArgs(element.DataContext));
}

So there you have it, the NavigationList, simple and fast.

Now people … please stop using ListBox for navigation, it is slow and it’s API is cumbersome!

You can download the sourcecode here:NavigationListControl.zip

Regards, Colin E.

MIX11 – A Tale of Two Keynotes – As Told By Twitter

April 14th, 2011

The annual MIX conference, where Microsoft showcases the latest and greatest technologies to the development community is now coming to an end. For many, the highpoints of the event are the keynote presentations, where Microsoft unveils their latest tools and technology. The keynotes are broadcast live across the internet and are followed by thousands of developers online as well as at the conference centre in Vegas. Unfortunately the keynotes both fell at a time when I was traveling home from work so I could not watch them live. However, I was able to follow the amazing buzz on twitter via the #mix11 hashtag.

Judging by the twitter buzz the two keynotes were very different, the first focusing on IE9 / IE10, HTML5 and a few other bits and pieces. The lack of Silverlight in the keynote frustrated quite a few followers and resulted in some pretty ridiculous journalism, for example ZDNETs Microsoft de-emphasizes Silverlight at Mix11. For many I think the second keynote is what they were waiting for with demonstrations of WP7 Mango and Silverlight 5 each of which will be bringing with them lots of exciting new features.

In order to capture the difference between the keynotes, I grabbed all the #mix11 tweets from April 12 (11,799) and April 13 (14,334), most of which were during the keynotes, and rendered them as a word cloud (using the lovely wordle):

I think the above images are a fascinating illustration of the two keynotes. The first is very busy, with many terms mentioned – although few do standout, HTML5 and IE10. Interestingly Silverlight and WP7 are highlighted in the cloud, even though neither were mentioned in the keynote. Most of the tweets mentioning these terms were along the lines of “What about Silverlight and WP7?”. Day two was clearly the day of WP7, Silverlight, Mango and Kinect, these terms stand out a mile!

Regards, Colin E.

Gartner Predicts a Promising Future for Windows Phone 7 Developers

April 8th, 2011

Yesterday Gartner released its latest mobile smartphone sales predications, with the figures showing a dramatic turnaround in their predictions for the Microsoft Windows Phone 7 platform. The latest predictions are charted below (I find this much easier to visualise this data in a chart versus the tabular form which Gartner publish!):

We can see from the chart above that Gartner predicts that Android will increase the lead that it has so rapidly acquired, BlackBerry’s RIM and Apple’s iOS will see moderate growth, whilst Microsoft will rise as Nokia’s Symbian declines, with the headline grabbing prediction being that Windows Phone 7 will outsell iPhone by 2015. It is also worth noting that net smartphones sales are predicted to hit 1 billion by 2015, that’s twice the sales figures expected for desktop PCs.

The prediction that there will be two smartphones sold for every one PC highlights just how important smartphones are as a platform for application developers. Regardless of OS, smartphones are powerful enough to support almost any application that you might have targeted for desktop production, therefore, if a smartphone version of your application is not on your roadmap, you are potentially missing out on 66% of your customers!

So how does Gartner’s most recent prediction compare to their previous one? If we chart their predictions for Symbian and Microsoft that they released in August 2010, the difference is quite clear (previous predictions shown as a dotted line):

Where previously they had predicted a strong rise in Symbian sales, and a poor uptake in Windows Phone 7, the tables are now turned.This is of course due to the recent news that Nokia are dropping their own Symbian OS in favour of Microsoft’s Windows Phone 7, with the first Nokia devices expected at the end of this year.

It is also interesting to look at how Gartner’s predictions have changed for RIM, iOS and Android from August 2010 to April 2011:

The predictions for RIM are unchanged, whilst they have increased their forecast sales prediction of iOS a little. However, they have dramatically increased their Android predications, so whilst Windows Phone 7 developers will certainly see Gartner’s latest figures as great news, it is clear that Gartner see the recent success of Android continuing and its market share increasing.

As others have reported, the smartphone market is highly volatile. The Nokia / Microsoft partnership has had a major impact on Gartner’s view of the near future, I expect that other significant events will occur between now and 2015 that these will have an equal impact on Gartner’s latest predictions, changing the landscape once again.

None-the-less, it is still a good day for Windows Phone 7 developers, Silverlight or XNA.

Regards, Colin E.