Colin Eberhardt's Adventures in WPF

Linq to Visual Tree

March 4th, 2010

This blog post demonstrates a Linq API which can be used to query the WPF / Silverlight Visual Tree. You can find a few other Linq to Visual Tree techniques on other blogs, but what makes this one unique is that it retains, and allows queries that make use of the tree like structure rather than simply flattening it.

I have recently published an article on codeproject which describes a technique for generating Linq API for querying tree-like structures. This blog post makes use of a generated API for WPF / Silverlight. If you are interested in the more generic approach, and how this API was constructed, (and how it is influenced by XPath) head on over to codeproject …

What I will provide here is a brief overview of the Linq to Visual Tree API. The full sourcecode for this API is at the end of this article.

The Linq to Visual Tree API defines a number of extension methods on DependencyObject that provide mechanisms for navigating to other DependencyObject instances. I will provide a few examples that query the following simple markup:

<Grid x:Name="GridOne" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
 
    <TextBox x:Name="TextBoxOne" Text="One" Grid.Row="0" />
 
    <StackPanel x:Name="StackPanelOne" Grid.Row="1">
        <TextBox x:Name="TextBoxTwo" Text="Two" />
 
        <Grid x:Name="GridTwo">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
 
            <TextBox x:Name="TextBoxThree" Text="Three" Grid.Row="0" />
 
            <StackPanel x:Name="StackPanelTwo" Grid.Row="1">
                <TextBox x:Name="TextBoxFour" Text="Four"/>                    
            </StackPanel>
        </Grid>
    </StackPanel>
</Grid>

We’ll start with a simple example. Include the Linq to Visual Tree namespace, then use the Descendants method to obtain all the descendants (i.e. children and children’s children, etc …) of an object within the
visual tree.

Descendants

using LinqToVisualTree;
 
// all items within the visual tree
IEnumerable<DependencyObject> allDescendants = this.Descendants();
/*
gives ...
0 {Grid} 	[GridOne]
1 {TextBox} 	[TextBoxOne]
2 {StackPanel} 	[StackPanelOne]
3 {TextBox} 	[TextBoxTwo]
4 {Grid} 	[GridTwo]
5 {TextBox} 	[TextBoxThree]
6 {StackPanel} 	[StackPanelTwo]
7 {TextBox} 	[TextBoxFour]
*/
 
// all items within the visual tree of 'GridTwo'
var descendantsOfGridTwo = GridTwo.Descendants();
/*
gives ...
0 {TextBox} 	[TextBoxThree]
1 {StackPanel} 	[StackPanelTwo]
2 {TextBox} 	[TextBoxFour]
*/

Each of the extension methods also has a corresponding method with a generic type parameter that filters the collection to find elements of a specific type:

// all items within the visual tree of 'GridTwo' that are textboxes
var textBoxDescendantsOfGridTwo = GridTwo.Descendants()
                                         .Where(i => i is TextBox);
/*
0 {TextBox} 	[TextBoxThree]
1 {TextBox} 	[TextBoxFour]
*/
 
// a shorthand using the generic version of Descendants
var textBoxDescendantsOfGridTwo2 = GridTwo.Descendants<TextBox>();
/*
0 {TextBox} 	[TextBoxThree]
1 {TextBox} 	[TextBoxFour]
*/

Elements

The elements extension method obtains all the direct children of an item in the visual tree:

// find all direct children of this user control 
var userControlChildren = this.Elements();
/*
0 {Grid} 	[GridOne]
*/
 
// find all direct children of the grid 'GridTwo'
var gridChildren = GridTwo.Elements();
/*
0 {TextBox} 	[TextBoxThree]
1 {StackPanel} 	[StackPanelTwo]
*/
 
// find all direct children of the grid 'GridTwo' that are StackPanels
var gridChildren2 = GridTwo.Elements<StackPanel>();
/*
0 {StackPanel} 	[StackPanelTwo]
*/

There are also, ElementsBeforeSelf and ElementsAfterSelf methods that return the elements before and after the item which the method is being invoked upon.

Ancestors

The ancestors methods traverse the tree towards the root, finding all the ancestors:

// the ancestors for 'TextBoxFour'
var ancestors = TextBoxFour.Ancestors();
/*
0 {StackPanel} 	[StackPanelTwo]
1 {Grid} 	[GridTwo]
2 {StackPanel} 	[StackPanelOne]
3 {Grid} 	[GridOne]
4 {MainPage} 	[]
*/
 
// the ancestors for 'TextBoxFour' that are StackPanels
var stackPanelAncestors = TextBoxFour.Ancestors<StackPanel>();
/*
0 {StackPanel} 	[StackPanelTwo]
1 {StackPanel} 	[StackPanelOne]
*/

Putting it all together

The Linq to Tree API not only defines extension methods on DependencyObject, but also the same extension methods on IEnumerable<DependencyObject>. Unless you have previous experience of Linq to XML, I would strongly suggest reading my codeproject article to understand how this works!

This allows you to form much more complex queries. For example, you can find all TextBoxs that have a Grid as a direct parent:

var itemsFluent = this.Descendants<TextBox>()
                      .Where(i => i.Ancestors().FirstOrDefault() is Grid);
 
var itemsQuery = from v in this.Descendants<TextBox>()
                 where v.Ancestors().FirstOrDefault() is Grid
                 select v;
/*
0 {TextBox} 	[TextBoxOne]
1 {TextBox} 	[TextBoxThree]
*/

Here, you can also see we are mixing the fluent and query syntax for Linq. Both give the same result.

The next example finds all StackPanels that are within another StackPanels visual tree:

var items2Fluent = this.Descendants<StackPanel>()
                              .Descendants<StackPanel>();
 
var items2Query = from i in
                      (from v in this.Descendants<StackPanel>()
                       select v).Descendants<StackPanel>()
                  select i;
/*
0 {StackPanel} 	[StackPanelTwo]
*/

Finally, this one-liner, outputs the entire visual tree in ASCII! It makes use of the DescendantsAndSelf, Ancestors and ElementsBeforeSelf methods, plus the funky Linq Aggregate method.

string tree = this.DescendantsAndSelf().Aggregate("",
    (bc, n) => bc + n.Ancestors().Aggregate("", (ac, m) => (m.ElementsAfterSelf().Any() ? "| " : "  ") + ac,
    ac => ac + (n.ElementsAfterSelf().Any() ? "+-" : "\\-")) + n.GetType().Name + "\n");
\-MainPage
  \-Grid
    +-TextBox
    | \-Grid
    |   +-Border
    |   | \-Grid
    |   |   +-Border
    |   |   \-Border
    |   |     \-ScrollViewer
    |   |       \-Border
    |   |         \-Grid
    |   |           +-ScrollContentPresenter
    |   |           | \-TextBoxView
    |   |           +-Rectangle
    |   |           +-ScrollBar
    |   |           \-ScrollBar
    |   +-Border
    |   +-Border
    |   \-Border
    |     \-Grid
    |       +-Path
    |       \-Path
    \-StackPanel
      +-TextBox
      | \-Grid
      |   +-Border
      |   | \-Grid
      |   |   +-Border
      |   |   \-Border
      |   |     \-ScrollViewer
      |   |       \-Border
      |   |         \-Grid
      |   |           +-ScrollContentPresenter
      |   |           | \-TextBoxView
      |   |           +-Rectangle
      |   |           +-ScrollBar
      |   |           \-ScrollBar
      |   +-Border
      |   +-Border
      |   \-Border
      |     \-Grid
      |       +-Path
      |       \-Path
      \-Grid
        +-TextBox
        | \-Grid
        |   +-Border
        |   | \-Grid
        |   |   +-Border
        |   |   \-Border
        |   |     \-ScrollViewer
        |   |       \-Border
        |   |         \-Grid
        |   |           +-ScrollContentPresenter
        |   |           | \-TextBoxView
        |   |           +-Rectangle
        |   |           +-ScrollBar
        |   |           \-ScrollBar
        |   +-Border
        |   +-Border
        |   \-Border
        |     \-Grid
        |       +-Path
        |       \-Path
        \-StackPanel
          \-TextBox
            \-Grid
              +-Border
              | \-Grid
              |   +-Border
              |   \-Border
              |     \-ScrollViewer
              |       \-Border
              |         \-Grid
              |           +-ScrollContentPresenter
              |           | \-TextBoxView
              |           +-Rectangle
              |           +-ScrollBar
              |           \-ScrollBar
              +-Border
              +-Border
              \-Border
                \-Grid
                  +-Path
                  \-Path

Note: this was invoked after the LayoutUpdated event so that we not only see the elements from our XAML, but also the elements created from their templates, giving us our full run-time visual tree.

You can download a simple Silverlight application that demonstrated all the examples given above:
LinqToTree.zip.

Or, if you just want the Linq to VisualTree code, you can copy-n-paste from the windows below which has the entire API, which includes the methods illustrated above,, plus their IEnumerable equivalents, and a few others I have not illustrated.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace LinqToVisualTree
{
    /// 
    /// Adapts a DependencyObject to provide methods required for generate
    /// a Linq To Tree API
    /// 
    public class VisualTreeAdapter : ILinqTree
    {
        private DependencyObject _item;

        public VisualTreeAdapter(DependencyObject item)
        {
            _item = item;
        }

        public IEnumerable Children()
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(_item);
            for (int i = 0; i < childrenCount; i++)
            {
                yield return VisualTreeHelper.GetChild(_item, i);
            }
        }

        public DependencyObject Parent
        {
            get
            {
                return VisualTreeHelper.GetParent(_item);
            }
        }
    }
}

namespace LinqToVisualTree
{
    /// 
    /// Defines an interface that must be implemented to generate the LinqToTree methods
    /// 
    /// 
    public interface ILinqTree
    {
        IEnumerable Children();

        T Parent { get; }
    }

    public static class TreeExtensions
    {
        /// 
        /// Returns a collection of descendant elements.
        /// 
        public static IEnumerable Descendants(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;

                foreach (var grandChild in child.Descendants())
                {
                    yield return grandChild;
                }
            }
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// 
        public static IEnumerable DescendantsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var child in item.Descendants())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of ancestor elements.
        /// 
        public static IEnumerable Ancestors(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);

            var parent = adapter.Parent;
            while (parent != null)
            {
                yield return parent;
                adapter = new VisualTreeAdapter(parent);
                parent = adapter.Parent;
            }
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// 
        public static IEnumerable AncestorsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var ancestor in item.Ancestors())
            {
                yield return ancestor;
            }
        }

        /// 
        /// Returns a collection of child elements.
        /// 
        public static IEnumerable Elements(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of the sibling elements before this node, in document order.
        /// 
        public static IEnumerable ElementsBeforeSelf(this DependencyObject item)
        {
            if (item.Ancestors().FirstOrDefault() == null)
                yield break;
            foreach (var child in item.Ancestors().First().Elements())
            {
                if (child.Equals(item))
                    break;
                yield return child;
            }
        }

        /// 
        /// Returns a collection of the after elements after this node, in document order.
        /// 
        public static IEnumerable ElementsAfterSelf(this DependencyObject item)
        {
            if (item.Ancestors().FirstOrDefault() == null)
                yield break;
            bool afterSelf = false;
            foreach (var child in item.Ancestors().First().Elements())
            {
                if (afterSelf)
                    yield return child;

                if (child.Equals(item))
                    afterSelf = true;
            }
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// 
        public static IEnumerable ElementsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var child in item.Elements())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of descendant elements which match the given type.
        /// 
        public static IEnumerable Descendants(this DependencyObject item)
        {
            return item.Descendants().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of the sibling elements before this node, in document order
        /// which match the given type.
        /// 
        public static IEnumerable ElementsBeforeSelf(this DependencyObject item)
        {
            return item.ElementsBeforeSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of the after elements after this node, in document order
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAfterSelf(this DependencyObject item)
        {
            return item.ElementsAfterSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all descendant elements
        /// which match the given type.
        /// 
        public static IEnumerable DescendantsAndSelf(this DependencyObject item)
        {
            return item.DescendantsAndSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of ancestor elements which match the given type.
        /// 
        public static IEnumerable Ancestors(this DependencyObject item)
        {
            return item.Ancestors().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements
        /// which match the given type.
        /// 
        public static IEnumerable AncestorsAndSelf(this DependencyObject item)
        {
            return item.AncestorsAndSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of child elements which match the given type.
        /// 
        public static IEnumerable Elements(this DependencyObject item)
        {
            return item.Elements().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAndSelf(this DependencyObject item)
        {
            return item.ElementsAndSelf().Where(i => i is T).Cast();
        }

    }

    public static class EnumerableTreeExtensions
    {
        /// 
        /// Applies the given function to each of the items in the supplied
        /// IEnumerable.
        /// 
        private static IEnumerable DrillDown(this IEnumerable items,
            Func> function)
        {
            foreach (var item in items)
            {
                foreach (var itemChild in function(item))
                {
                    yield return itemChild;
                }
            }
        }

        /// 
        /// Applies the given function to each of the items in the supplied
        /// IEnumerable, which match the given type.
        /// 
        public static IEnumerable DrillDown(this IEnumerable items,
            Func> function)
            where T : DependencyObject
        {
            foreach (var item in items)
            {
                foreach (var itemChild in function(item))
                {
                    if (itemChild is T)
                    {
                        yield return (T)itemChild;
                    }
                }
            }
        }

        /// 
        /// Returns a collection of descendant elements.
        /// 
        public static IEnumerable Descendants(this IEnumerable items)
        {
            return items.DrillDown(i => i.Descendants());
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// 
        public static IEnumerable DescendantsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.DescendantsAndSelf());
        }

        /// 
        /// Returns a collection of ancestor elements.
        /// 
        public static IEnumerable Ancestors(this IEnumerable items)
        {
            return items.DrillDown(i => i.Ancestors());
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// 
        public static IEnumerable AncestorsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.AncestorsAndSelf());
        }

        /// 
        /// Returns a collection of child elements.
        /// 
        public static IEnumerable Elements(this IEnumerable items)
        {
            return items.DrillDown(i => i.Elements());
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// 
        public static IEnumerable ElementsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.ElementsAndSelf());
        }

        /// 
        /// Returns a collection of descendant elements which match the given type.
        /// 
        public static IEnumerable Descendants(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Descendants());
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// which match the given type.
        /// 
        public static IEnumerable DescendantsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.DescendantsAndSelf());
        }

        /// 
        /// Returns a collection of ancestor elements which match the given type.
        /// 
        public static IEnumerable Ancestors(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Ancestors());
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// which match the given type.
        /// 
        public static IEnumerable AncestorsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.AncestorsAndSelf());
        }

        /// 
        /// Returns a collection of child elements which match the given type.
        /// 
        public static IEnumerable Elements(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Elements());
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.ElementsAndSelf());
        }
    }
}

Regards, Colin E.

The mini-ViewModel pattern

August 7th, 2009

The construction of a ViewModel is often seen as the standard technique for solving binding problems within WPF and Silverlight. However, the addition of a ViewModel adds complexity to your code. This post describes an alternative method where a mini-ViewModel is applied directly to the problem areas in the view, leaving the rest to use simpler, straightforward binding to business objects.

One of the features of WPF / Silverlight that appealed to me immediately when I started to learn it was the flexibility of the binding framework. The concepts of DataContext inheritence and flexibility of the value converters results in a lot less glue-code, which makes me a happy developer! However, it does not take long before you start finding examples that just dont fit with the framework and things start to get just little more complex. This blog post describes one such example.

The example used in this blog post is of a very simple application which displays a business card. The business object rendered by the application, ContactDetails, has a number of simple CLR properties. Constructing a UI for viewing this business object is very easy, simply create an instance of this object (in a real application this object might come from a database or web service) and set it as the DataContext of the view:

public Page()
{
    InitializeComponent();
 
    ContactDetails details = new ContactDetails()
    {
        Company = "Scott Logic Ltd.",
        Email = "ceberhardt@scottlogic.co.uk",
        URL = "http://www.scottlogic.co.uk",
        Country = "UK",
        FullName = "Colin Eberhardt",
        PhoneNumber = 4408452241930
    };
 
    this.DataContext = details;
}

We then create some simple XAML with UI elements that bind to the various propeties of our object …

<Grid x:Name="LayoutRoot" Background="White">
    <Border BorderBrush="LightGray" Background="White"  BorderThickness="1.5" CornerRadius="20"
        VerticalAlignment="Center" HorizontalAlignment="Center">
        <Border Margin="5" BorderBrush="LightGray" BorderThickness="1.5" CornerRadius="15">
            <Border.Background>
                <ImageBrush>
                    <ImageBrush.ImageSource>
                        <BitmapImage UriSource="back.jpg" />
                    </ImageBrush.ImageSource>
                </ImageBrush>
            </Border.Background>
 
            <StackPanel Orientation="Vertical" Margin="10">
                <TextBlock Text="{Binding FullName}"
                           FontSize="15"
                           FontWeight="Bold" />
                <Rectangle Stroke="DarkGray" HorizontalAlignment="Stretch"
                           StrokeThickness="0.5" Height="1"/>
                <TextBlock Text="{Binding Company}" Margin="0,10,0,0"/>
                <StackPanel Orientation="Horizontal" >
                    <TextBlock Text="e: "/>
                    <TextBlock Text="{Binding Email}" />
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="w: "/>
                    <HyperlinkButton Content="{Binding URL}"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="p: "/>
                    <TextBlock Text="{Binding PhoneNumber}"/>
                </StackPanel>
            </StackPanel>
        </Border>
    </Border>
</Grid>

And we get a lovely looking business card:

card

One problem with the above example is the phone number, outputting the raw number ‘4408452241930′ is not terribly readable, besides phone numbers have a standard format, in this case, the phone number would be represented as ‘+44 (0)845 2241930′. Also, let’s make the problem more interesting; you might want to highlight the international dialing code in a different colour, or, if the application is being used by a UK client, display the number in a local format without the international code ‘0845 2241930′. So just how do we achieve this?

In order to break the number up into different blocks of text, with different colours (i.e. styles), we need to modify our view to have multiple TextBlocks mapped to the PhoneNumber property of our business object. The part of our view which renders the phone number is modified as follows:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="p: "/>
    <TextBlock Text="... country code ..." Foreground="LightGray"/>
    <TextBlock Text="... area code ..."/>
    <TextBlock Text="... local number ..."/>
</StackPanel>

But just how exactly do we bind the properties of these business objects?

One approach would be to use a value converter for each binding in order to extract the required part of the number, for example a CountryCodeValueConverter could be implemented which grabs the first 2 digits of the number. However, this approach is a little inelligent in that it fragments our logic into a number of separate classes, furthermore, if we want country specific formatting this requires the use of multibindings, which can be rather cumbersome if over-used (for a Silverlight implementation of multi bindings see my blog post from earlier this year).

Another approach which is often used to tackle tricky binding problems is the use of the Model-View-ViewModel (MVVM) pattern. With this pattern, our ContactDetails object is the Model, we construct a ViewModel which is a UI-oriented abstraction of the Model and it is this which we bind to the View. WPF guru Josh Smith describes MVVM as “a value converter on steroids” in order to highlight the usefulness of the pattern in this context.

The basic approach used here is to bind your View to a ViewModel rather than binding it to the business object directly. The ViewModel is specific to the view and wraps the business object (i.e. Model), forwarding the property values and change notification to the View. This extra layer allows us to supplement the properties of the Model object, adding new computed properties which are specific to the View. In this case, these computed properties can be used to expose ‘country code’, ‘area code’, etc… to our View.

(This is a common pattern so I am not going to reproduce the code required here, however, if you are interested, the attached sourcecode accompanying this article contains a regular ViewModel version as well as a mini-ViewModel implementation)

Whilst this approach works, my issue with it is that it adds quite a bit of boiler-plate code for wrapping properties, forwarding events etc … The removal of this glue-code is the exact reason that I like WPF/Silverlight so much! The MVVM pattern is primarily for supporting the designer-developer paradigm and enabling unit testing of UI applications, in my opinion the use of MVVM for anything else is just plain wrong!

So, how can we solve the problem of providing a nicely formatted phone number without the pain of bashing out line-after-line line of boiler-plate MVVM code? My solution to the problem isn’t to dispose of the MVVM pattern altogether, rather, it is to localise its usage to just the problem area. The first step is to encapsulate the rendering of the phone number as a user control:

...
<StackPanel Orientation="Horizontal">
    <TextBlock Text="p: "/>
    <local:PhoneNumberControl Number="{Binding PhoneNumber}" />
</StackPanel>
...

… which probably makes sense anyway from a perspective of good design and code re-use!

Now that we have moved the phone number property within the PhoneNumberControl we have isolated the problem and can deal with it locally. We can create a PhoneNumberControlViewModel which splits the phone number up into its various components and bind this to the PhoneNumberControl.

The control’s ViewModel looks something like this:

public class PhoneNumberControlViewModel : INotifyPropertyChanged
{
    public PhoneNumberControlViewModel(PhoneNumberControl ctrl)
    {
        _ctrl = ctrl;
        ComputeProperties();
 
        // listen to property changes in the control (we are interested
        // in just the Number property)
        _ctrl.PropertyChanged += Control_PropertyChanged;
    }
 
    private PhoneNumberControl _ctrl;
 
    private string _countryCodeText;
 
    private string _areaCodeText;
 
    private string _localNumberText;
 
    public string CountryCodeText
    {
        get { return _countryCodeText; }
        set { _countryCodeText = value; OnPropertyChanged("CountryCodeText");  }
    }
 
    public string AreaCodeText
    {
        get { return _areaCodeText; }
        set { _areaCodeText = value; OnPropertyChanged("AreaCodeText"); }
    }
 
    public string LocalNumberText
    {
        get { return _localNumberText; }
        set { _localNumberText = value; OnPropertyChanged("LocalNumberText"); }
    }
 
    private void Control_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Number" || e.PropertyName == "Country")
        {
            ComputeProperties();
        }
    }
 
    private void ComputeProperties()
    {
        string formattedNumber = _ctrl.Number.ToString();           
        CountryCodeText = "+" + formattedNumber.Substring(0, 2);
        AreaCodeText = " (" + formattedNumber.Substring(2, 1) + ")" + formattedNumber.Substring(3, 3);
        LocalNumberText = " " + formattedNumber.Substring(6);
    }
}

Note that here the ViewModel is ‘wrapping’ the PhoneNumberControl rather than an instance of some Business / Model object.

Now we just set our ViewModel as the DataContext for the View, as per the typical usage of this pattern:

public PhoneNumberControl()
{
    InitializeComponent();
 
    this.DataContext = new PhoneNumberControlViewModel(this);
}

… and it doesn’t work. If you try the above, you will find that the binding on the PhoneNumberControls Number property no longer works. So why is this? if you look back at where the PhoneNumberControl instance is defined in our business card’s XAML markup you see that its Number property is bound as follows:

<local:PhoneNumberControl Number="{Binding PhoneNumber}" />

The source of this binding is not explicitly set, so will default to using the DataContext of the PhoneNumberControl instance. However, we have just changed this DataContext in our constructor to something else … oops!

Solving this problem is actually quite simple, the PhoneNumberControl markup is as follows:

<UserControl x:Class="SLMiniViewModel.PhoneNumberControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel x:Name="LayoutRoot" Orientation="Horizontal">
        <TextBlock Text="{Binding CountryCodeText}" Foreground="DarkGray"/>
        <TextBlock Text="{Binding AreaCodeText}"/>
        <TextBlock Text="{Binding LocalNumberText}"/>
    </StackPanel>
</UserControl>

If we modify our binding to the ViewModel as follows:

public PhoneNumberControl()
{
    InitializeComponent();
 
    LayoutRoot.DataContext = new PhoneNumberControlViewModel(this);
}

The subtle difference being that the ViewModel is now bound to the StackPanel which is the root of our visual tree within the control. This means that the PhoneNumberControl DataContext is still inherited from the business card and is our business object instance, the DataContext switch to the ViewModel is now neatly tucked just within the PhoneNumberControls visual tree, and it is this DataContext which our TextBlocks will inherit and bind to.

The result is that we can now use our mini-ViewModel embedded within the PhoneNumberControl to expose properties which are more amenable to binding to our View:

card2

Whilst this is a quite trivial example, in real-world applications, more complex examples where the data representation within the View is dependant on a number of properties are quite common. The source code accompanying this article extends the example a little further by making the formatting dependant on a second property of the business object. This is the sort of problem that would either push you towards multi-binding and numerous fragmented value converters, or a ViewModel.

In conclusion, the use of a mini-ViewModel which is embedded within a UserControl allows you to solve tricky binding problems without being weighed down by rolling out the MVVM pattern across your entire View. I am not against the MVVM pattern in itself, however I do firmly believe that it should only be used to solve the problems which it is was specifically designed for, i.e. supporting the designer-developer workflow and unit testing.

You can download the source-code for this article: SLMiniViewModel.zip – this project contains both MVVM and mini-MVVM implementations (count the number of lines in the ViewModel and contrast it with the mini-ViewModel).

Regards, Colin E.

Silverlight v3 ClearType Font Rendering – A comparison

July 14th, 2009

Text rendering has been a problem for both Silverlight and WPF for a while. This blog post looks at ClearType in Silverlight v3 and compares it to WPF and WinForms text rendering.

Text clarity is something that concerns me quite a bit. In financial applications, such as our market overview pages, often large quantities of both graphical and textual data are rendered to the screen. Users of these applications need to be able to rapidly digest information, hence clarity is very important.

I was very happy to see that text rendering in Silverlight has been improved by the introduction use of the ClearType sub-pixel rendering algorithm. The following table contrasts the same Tahoma text rendering using Silverlight, WPF and WinForms in order to compare the text clarity.

To scale Zoom x4
Silverlight v2.0 silverlight2 silverlight2-zoom
Silverlight v3.0
(ClearType on)
silverlight3 silverlight3-zoom
WPF
(ClearType off
)
wpf wpf-zoom
WPF
(ClearType on)
wpf-cleartype wpf-cleartype-zoom
WinForms
(ClearType off)
winforms winforms-zoom
WinForms
(ClearType on)
winforms-cleartype winforms-cleartype-zoom

From the above table you can see the tell-tale colour-halos around text in Silverlight v3.0 indicating that ClearType rendering is being used. Previously Silverlight used the same anti-aliasing approach used by WPF.

The text rendering of WPF has been criticised quite a bit. The main problem is that text glyphs are not snapping to pixel boundaries, which results in some rather unpleasant artefacts when text is animated. However, the good news is that this will be fixed in .NET 4.0.

The addition of ClearType text rendering in Silverlight v3.0 is certainly good news. However, if you compare the images above, I still find that the WinForms ClearType rendered text is clearer that its WPF / Silverlight counterparts. If you inspect the word ‘bold’ which is rendered in white text on a blue background, the WinForms text is much clearer. The WPF / Silverlight fonts appear much ‘fatter’ with less space between the letters. All the above applications used exactly the same font (Tahoma) and the same font size.

Regards, Colin E.

Silverlight 3 UK launch … and the future of WPF?

July 9th, 2009

A brief article on the launch of Silverlight 3 and why the interest in Silverlight is eclipsing that of WPF.

The excitement behind Silverlight has been gaining in momentum throughout this year, with one of the highpoints being the MIX09 conference in March this year where the announcement of Silverlight 3 beta took centre stage. There are no signs of this momentum having dropped with the final version of Silverlight 3 being release tomorrow, on July 10th.

I will be attending the UK launch of Silverlight 3, together with our MD Gary Scott, at the MS Offices in London.

invite

… for some reason, we in the UK are 12 days behind the rest of the world ;-)

I came to Silverlight through its big-brother WPF about half a year ago. I was looking for a new challenge and WPF certainly delivered, the framework has an elegance that leaves its predecessor WinForms looking clunky and second-rate. Silverlight shares this same elegance, some of the finer details are missing (Triggers, 3D, double-click events!), however there are enough similarities that a WPF developer can pick up Silverlight in a matter of hours, furthermore developing applications that target both frameworks is quite straightforward.

Since making the move to Silverlight I have done very little with WPF. I have found that my Silverlight blog posts and articles have proved far more popular than their WPF counterparts. Also, our customers here at Scott Logic are showing an increasing interest in Silverlight, but rarely mention WPF. So why is this?

Most companies within the financial sector follow a similar archetype; with their desktop software being most typically developed with WinForms (or Excel!), and a seemingly equal split between companies whose web offerings are developed on a Microsoft platform (ASP.NET) or Sun Java (J2EE).

If we think for a moment about what WPF could mean for companies such as these; personally I think the answer is unfortunately very little. WPF revolutionises the way in which the UI is assembled and connects to your business objects, as a developer I think it is great! However, is that enough to convince the management that they should ditch their WinForms development and invest in WPF? I don’t think it is. Whilst the developers will enjoy the switch to WPF, what’s in it for the end users – skinning? rounded borders? (blurry fonts? – ahem). If there is no perceived end-user benefit or reduced development cost, there are no compelling reasons to adopt WPF. Interestingly Microsoft’s Tim Sneath mentioned that the early expectations for WPF were that it would be  “primarily for consumer software”, although he does allude to adoption of WPF for enterprise software – sorry Tim, I just don’t see it happening from here!

The story for Silverlight is very different. Delivering interactive web applications has always been a struggle, the use of AJAX to retrofit interactivity on top of what is essentially a static presentation model, HTML, is a constant battle. However, interactivity and a rich UI is something that all end-users want … and Silverlight certainly delivers. This is the reason why Silverlight is gaining interest not just from the developers, but also from their managers (and their manager’s managers). Interestingly those companies that develop their web-offerings with Sun Java seem to be as interested in Silverlight as their Microsoft ASP.NET counterparts.


tortoise

With Silverlight starting on what looks like a winning streak, what is the future for WPF? Some people are of the belief that Silverlight will eventually kill of WPF, however I do not share that view. Personally I think that WPF will be eclipsed by the shadow of Silverlight for a few years for the reasons given above. However, I think that WPF is the Tortoise to Silverlight’s Hare; as companies start to adopt Silverlight their developers will gain the expertise necessary to develop WPF applications. My thinking is that in a few years time, when these companies embark on new desktop software developments, it is not the features of WPF that will steer them towards WPF, but rather their developer skillset.

The immediate future for Silverlight looks very bright.

Or is it? … Unfortunately not. Our customers want to use Silverlight, but so often they cannot because they know their users do not have the required plugin to run Silverlight applications. The problem is that the end-users will probably not install Silverlight until they have a reason to, a sort of Chicken or the Egg problem. With statistics indicating that approximately 25% of users having Silverlight installed, this is a big problem.

So, back to the Silverlight 3 UK Launch, if there is a QA session, there is only one question that I really need to ask, and that is:

quote Ian, as a developer I am sold on Silverlight. The release of version 3 put the icing on a cake that is already quite sweet. But what is Microsoft doing to help user-adoption of the plugin? quote

Regards, Colin E.