Colin Eberhardt's Adventures in WPF

Silverlight MultiBinding updated, adding support for ElementName and TwoWay binding

August 12th, 2010

This blog post describes an update to the Silverlight 4 MultiBinding technique I blogged about a couple of months ago to add support for ElementName binding and TwoWay binding.

A few months ago I posted an update to my MultiBinding solution for Silverlight 4. This technique allows you to perform the same kind of multibindings which are possible in WPF, where a property value is bound to multiple sources via a special value converter that implements the IMultiValueConverter interface, which describes how these values are combined. This update proved popular once again, and I received a few requests to add support for ElementName and TwoWay binding. I like challenge! This blog post describes how these two features were implemented, but if you just want to grab the code, you will find the link at the end of this article.

A brief recap

Before I go into the implementation details for the new features I will provide a brief recap of how my multibinding solution works. The XAML for creating a multibinding looks like the following:

<TextBlock Foreground="White" 
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                          Converter="{StaticResource TitleConverter}">
        <local:BindingCollection>
          <Binding Path="Surname"/>
          <Binding Path="Forename"/>
        </local:BindingCollection>
      </local:MultiBinding>
      <local:MultiBinding TargetProperty="ToolTipService.ToolTip"
                          Converter="{StaticResource TitleConverter}">
        <local:BindingCollection>
          <Binding Path="Surname"/>
          <Binding Path="Forename"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>

Here the Text property and attached ToolTip property of the TextBlock are bound to both the Surname and Forename property of the business object which is set as the DataContext of our view.

The value converter is as follows:

public class TitleConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType,
    object parameter, CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
 
  ...
}

In the example below you can see that as you change the forename or surname, the title text and tooltip are updated by the multibinding.

So how does this work?

When a multibinding is created and added to an element via the BindingUtil.MultiBindings attached property, the MultiBinding instance is added to a virtual-branch, this is a branch of the visual tree that obtains the DataContext of the element to which it is bound, but is not added to the visual tree itself. The MultiBinding then creates a BindingSlave instance for each of the given Bindings. These ‘slave’ elements inherit the MultiBinding DataContext and are used to evaluate each of the individual Bindings. The MultiBinding instance aggregate the results of each binding with the IMultiValueConverter used to compute the ConvertedValue property which is bound to the target property on the element to which this MultiBinding as attached.

ElementName binding

So why does the above solution not work if one of the multibindings uses ElementName to locate the source rather than using the inherited DataContext? The problem here is that the MultiBinding and its BindingSlave instances are located in a virtual branch and are therefore not in the same namescope as the target element. As a result, they cannot perform look up of named elements.

In order to solve this problem I created a BindingSlave subclass specifically for ElementName binding. This slave locates the source element named via the ElementName property and sets it as the Source of the binding it uses to compute its Value property.

The only minor complication I encountered is that the MultiBinding might be constructed before the element referenced via ElementName. For this reason the binding slave must handle LayoutUpdated events to ensure that the named element is located if it is constructed after the multibinding.

public class ElementNameBindingSlave : BindingSlave
{
  private FrameworkElement _multiBindingTarget;
 
  /// <summary>
  /// The source element named in the ElementName binding
  /// </summary>
  private FrameworkElement _elementNameSource;
 
  private Binding _binding;
 
  public ElementNameBindingSlave(FrameworkElement target, Binding binding)
  {
    _multiBindingTarget = target;
    _binding = binding;
 
    // try to locate the named element
    ResolveElementNameBinding();
 
    _multiBindingTarget.LayoutUpdated += MultiBindingTarget_LayoutUpdated;
  }
 
  /// <summary>
  /// Try to locate the named element. If the element can be located, create the required
  /// binding.
  /// </summary>
  private void ResolveElementNameBinding()
  {
    _elementNameSource = _multiBindingTarget.FindName(_binding.ElementName) as FrameworkElement;
    if (_elementNameSource != null)
    {
      SetBinding(BindingSlave.ValueProperty, new Binding()
      {
        Source = _elementNameSource,
        Path = _binding.Path,
        Converter = _binding.Converter,
        ConverterParameter = _binding.ConverterParameter
      });
    }
  }
 
  private void MultiBindingTarget_LayoutUpdated(object sender, EventArgs e)
  {
    // try to locate the named element 
    ResolveElementNameBinding();
  }
}

The example below demonstrates element name binding by binding the Value of two Slider elements to a TextBlock which displays the sum of the two values.

<TextBlock Grid.Column="1">
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                          Converter="{StaticResource SliderValueConverter}">
        <local:BindingCollection>
          <Binding ElementName="sliderOne" Path="Value"/>
          <Binding ElementName="sliderTwo" Path="Value"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBlock>
 
<Slider x:Name="sliderOne" Value="10"/>
 
<Slider x:Name="sliderTwo"  Value="20"/>

Here is the value converter that is used to compute the sum:

public class SliderValueConverter : IMultiValueConverter
{
 
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    if (values.Length != 2 ||
        values[0] == null ||
        values[1] == null)
      return null;
 
    return (double)values[0] + (double)values[1];
  }
 
  ...
}

You could of course use element name binding to combine the surname / forename in the first example in this blog post, but in this context it is more likely that you will want to back your UI with a business object. It is also possible to mix element name and regular (i.e. Source=DataContext) binding.

I find multibindings which use ElementName references most useful when creating complex UI layouts that do not lend themselves to being implemented using Panels. For a good example see my article on the implementation of a BulletGraph control which makes extensive use of this technique in order that the layout of the control is performed entirely within XAML.

TwoWay Binding

A two-way multibinding must be able to handle updates to the combined value and split it up into its constituent parts in order to update the multiple source bindings. In the first example where a forename and surname property are combined into a “surname, forename” string it is possible to convert back the other way, but in the example above where the values of two Sliders are combined a reverse conversion is not possible.

Modifying this multibinding solution to permit two way binding was relatively straightforward. A property changed event handler was added to the MultiBindig.ConverterValue (which is bound to the multi binding target) so that we can determine when changes have been made. This handler then uses the IMultiValueConverter to convert the value into the multiple source properties and updates the binding slaves accordingly:

/// <summary>
/// Handles property changes for the ConvertedValue property
/// </summary>
private void OnConvertedValuePropertyChanged()
{
    OnPropertyChanged("ConvertedValue");
 
    // if the value is being updated, but not due to one of the multibindings
    // then the target property has changed.
    if (!_updatingConvertedValue)
    {
      // convert back
      object[] convertedValues = Converter.ConvertBack(ConvertedValue, null,
          ConverterParameter, CultureInfo.InvariantCulture);
 
      // update all the binding slaves
      if (Children.Count == convertedValues.Length)
      {
        for (int index = 0; index < convertedValues.Length; index++)
        {
          ((BindingSlave)Children[index]).Value = convertedValues[index];
        }
      }
    }
}

In order to use two way multibinding both the multibinding mode and the bindings within the BindingCollection must be set to TwoWay. See the example given below:

<TextBlock Text="Surname:"/>
<TextBox  Grid.Column="1" Text="{Binding Path=Surname, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="1" Text="Forename:"/>
<TextBox Grid.Row="1"  Grid.Column="1" Text="{Binding Path=Forename, Mode=TwoWay}"/>
 
<TextBlock Grid.Row="2" Text="Combined:"/>
<TextBox Grid.Row="2"  Grid.Column="1" >
  <local:BindingUtil.MultiBindings>
    <local:MultiBindings>
      <local:MultiBinding TargetProperty="Text"
                        Converter="{StaticResource TitleConverter}"
                        Mode="TwoWay">
        <local:BindingCollection>
          <Binding Path="Surname" Mode="TwoWay"/>
          <Binding Path="Forename" Mode="TwoWay"/>
        </local:BindingCollection>
      </local:MultiBinding>
    </local:MultiBindings>
  </local:BindingUtil.MultiBindings>
</TextBox>

You can have try of two way multibinding below where the values of the forename and surname text boxes are combined in the box below. However, you ca also make updates to the combined result which will then be converted back into its constituent parts:

And here is the value converter:

public class TitleConverter : IMultiValueConverter
{
  #region IMultiValueConverter Members
 
  public object Convert(object[] values, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string forename = values[0] as string;
    string surname = values[1] as string;
 
    return string.Format("{0}, {1}", surname, forename);
  }
 
  public object[] ConvertBack(object value, Type[] targetTypes,
    object parameter, System.Globalization.CultureInfo culture)
  {
    string source = value as string;
    var pos = source.IndexOf(", ");
 
    string forename = source.Substring(pos + 2);
    string surname = source.Substring(0, pos);
 
    return new object[] { forename, surname };
  }
 
  #endregion
}

So, there you have it, two-way and element name multibinding :-)

You can download the full source, including a WPF build (thanks to Stefan Olson) here: SLMultiBinding.zip

Now … go forth and multibind.

Regards, Colin E.

A Universal Value Converter for WPF

July 9th, 2010

This post provides a simple IValueConverter implementation that makes use of the framework type converters in order to convert between a large range of source / target types. This converter can be used both within bindings and in code-behind to give more concise property setters.

Introduction

One of the great features of the XAML language is that it is flexible, concise and expressive (yes, I know that XML can be a little verbose, but if you try to create a complex UI purely in code-behind I think you will agree with my observations!). For example, you can set the fill of a rectangle by simply specifying the named color:

<Rectangle Fill="Green"/)

or … you can specify the RGB values directly:

<Rectangle Fill="#00FF00"/)

Looking at the above examples, you might be fooled into thinking that the Fill property is of type Color. People who are new to WPF often find that this is not the case the first time they try to bind a property of type Color to the Fill property (they would never set the Fill property directly in code behind, because that would be a cardinal sin!). The Fill property is actually of type Brush, and the XAML parser is performing some cunning type conversions in order to make the above markup work.

The solution to this problem of binding a Color to the Fill property is to create a value converter:

public class ColorToBrushConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    if (value is Color)
    {
      return new SolidColorBrush((Color)value);
    }
    return null;
  }
 
  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    throw new Exception("The method or operation is not implemented.");
  }
}

Which can be used as follows:

<Rectangle Fill="{Binding Path=MyColorProperty,
                                  Converter={StaticResource ColorToBrushConverter}} "/)

If you search google for ColorToBrushConverter, you can see that there are a great many people who have implemented this simple little converter. But what happens if you want to bind to a string representation of color? or you want to bind to a stroke dash property or path geometry? Whilst value converters are simple to implement, it is a shame that you have to create so many of them!

A Universal Value Converter

Wouldn’t it be great to have a single value converter that has the same flexibility as the XAML parser? It is actually very simple to create such as converter (and after creating probably my 5th ColorToBrushConverter I have no idea why it took so long before I realised this!). The .NET framework has had an API for conversion between different types via TypeConverters for a long time. They used extensively in .NET technologies for databinding and designer support, and much more.

A value converter can obtain a suitable TypeConverter for the target property then perform the required conversion:

public class UniversalValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // obtain the conveter for the target type
        TypeConverter converter = TypeDescriptor.GetConverter(targetType);
 
        try
        {
            // determine if the supplied value is of a suitable type
            if (converter.CanConvertFrom(value.GetType()))
            {
                // return the converted value
                return converter.ConvertFrom(value);
            }
            else
            {
                // try to convert from the string representation
                return converter.ConvertFrom(value.ToString());
            }
        }
        catch (Exception)
        {
            return value;
        }
 
    }
 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Note, that this value converter first tries to convert directly from the source to the target type, if this is not possible it then tried to convert via a string representation (I am not sure whether it is more correct to obtain a TypeConverter for the String type, then use this rather that invoking ToString on the value being converted, but the above works for me :-) ).

You can see this converter in action below where a range of type conversions are demonstrated:

<TextBlock Text="Converting String to Brush ...."/>
<Rectangle Fill="{Binding ElementName=colorTextBox, Path=Text, Converter={StaticResource UniversalValueConverter}}"/>
<TextBox x:Name="colorTextBox"
             Text="Red"/>
 
<TextBlock Text="Converting String to Geometry ...."/>
<Path Data="{Binding ElementName=geometryText, Path=Text, Converter={StaticResource UniversalValueConverter}}"/>
<TextBox x:Name="geometryText"                  
             Text="M 10,20 C 10,2.5 40,35 40,17 H 28"/>
 
<TextBlock Text="Converting String to DoubleCollection (stroke dash) ...."/>
<Line StrokeDashArray="{Binding ElementName=dashText, Path=Text, Converter={StaticResource UniversalValueConverter}}"/>
<TextBox x:Name="dashText"                  
            Text="2 2 4 5"/>

For the first conversion, string to brush, you can use named colors, and the hex notation in its range of abbreviated forms (#AF7, #AAFF77, #FFAAFF77 …). You can also use this converter to convert from string to their corresponding enum values, for example binding the string “Collapsed” to the Visbility property.

Value conversion in code behind

The above converter really is swiss army knife for bindings, but what about code-behind? You are still constrained by the type requirements of the property being set:

rect1.Fill = new SolidColorBrush()
{
    Color = Colors.Red
};

Value converters, whilst typically used in binding, can also be used directly in code-behind. The following extension method extends SetValue method for setting dependency properties to make use of the above value converter:

/// <summary>
/// Sets the given dependency property, applying type conversion where required
/// </summary>
public static void SetValueEx(this DependencyObject element, DependencyProperty property, object value)
{
    var conv = new UniversalValueConverter();
    var convertedValue = conv.Convert(value, property.PropertyType, null, CultureInfo.InvariantCulture);
    element.SetValue(property, convertedValue);
}

Which provides a more flexible mechanism for setting property values:

rect1.SetValueEx(Rectangle.FillProperty, Colors.Red);
rect2.SetValueEx(Rectangle.FillProperty, "Blue");
rect3.SetValueEx(Rectangle.FillProperty, "#FFEE55");
rect4.SetValueEx(Rectangle.FillProperty, new SolidColorBrush(Colors.Orange));

… and Silverlight?

Unfortunately Silverlight lacks the TypeDescriptor class which is used to obtain TypeConveters. I am guessing that type conversion within Silverlight is ‘baked-in’ to the XAML parser, which means that it is not possible to re-use this logic :-(

You can download the full source for this blog post: UniversalValueConverter.zip

Regards,
Colin E.

Modal dialogs in cross-platform WPF/Silverlight applications

June 18th, 2010

This blog post looks at the problem of showing modal dialog windows in applications that target both the Silverlight and WPF platforms. A solution is provided which allows modal dialogs to be written that work well for both technologies.

Silverlight is, roughly speaking, a subset of Windows Presentation Foundation (WPF). This means that it is possible to write applications that target both frameworks, allowing you to develop applications that work both on the desktop and on the web using the same codebase.

However, Silverlight is not a strict subset of WPF, the differences between the two frameworks can be summed up as follows:

  1. Things that WPF has that Silverlight does not
  2. Things that Silverlight has that WPF has not
  3. Things that both framework have but are different!

There are a great many things that the WPF framework has that Silverlight does not, mostly due to the size constraints of Silverlight being a browser plugin (1). There are a few things that Silverlight has, such as Out Of Browser (OOB) support and local storage which are not in WPF because they relate to the browser context (2). If these areas are avoided, the creation of a cross-platform application can be straightforward, however it is point (3) that causes problems.

When developing an application which targets both frameworks it makes sense to do most of your development primarily in Silverlight in order to avoid accidentally using WPF features. In practical terms the way most people  achieve this is to create two projects, one Silverlight, one WPF. The WPF project will include links to the files within the Silverlight project (This is achieved by selecting “Add existing item …”, then selecting the “Add as link” option). The following diagram highlights the linked files in the attached project:

The first obstacle to overcome is the entry point into the application. Silverlight applications render a single UserControl as the RootVisual of the instantiated application, wheres WPF applications will create a Window instance when launched. This problem is easily solved by simply hosting the UserControl, which is the starting point for the Silverlight application, within a Window:

<Window x:Class="ModalDialogDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ModalDialogDemo"
        Title="Modal dialog demo" SizeToContent="WidthAndHeight">
    <Grid>
        <local:MainControl/>
    </Grid>
</Window>

With this small obstacle cleared, you can create some pretty decent cross-framework applications (as long as you avoid the temptation of looking at all the WPF controls you are missing out on!).

I have created quite a few WPF / Silverlight applications in this manner, and the process, although a little clunky (I usually have two Visual Studio instances open so that I can keep the two versions in synch), works pretty well. However, the next major obstacle I experienced is that of creating a modal dialog. This falls firmly into category (3).

Modal dialog functionality was added in Silverlight 3. To pop-up a modal dialog, create a page which inherits from ChildWindow (rather than the usual UserControl). This class provides a Show method which pops up the dialog, and a Closed event which is raised when the user hits the OK or Cancel. For example, you might create an error dialog and use it as follows:

ErrorDialog dlg = new ErrorDialog ();
dlg.Closed += new EventHandler(OnErrorDialogClosed);
dlg.Show();

Visual Studio has a template for the creating of modal dialogs via ChildWindow:

However, with WPF things are a bit different. Whilst Silverlight modal dialogs are constrained to live within the Silverlight container on your web page, WPF dialogs are proper windows that you can move around your desktop (Interestingly, someone on stackoverflow has emulated Silverlight’s ChildWindow in WPF, although I am not convinced that this will look right on a desktop application). Visual Studio does not have a template for creating modal dialogs in WPF, however, there is more than enough documentation regarding the various types of dialog on MSDN.

With WPF a Window can be shown as modal as follows:

ErrorDialog dlg = new ErrorDialog ();
dlg.ShowDialog();

There are a few differences here, firstly Window has a Show method just like Silverlight’s ChildWindow, however, this will result in showing a modeless window. Instead we invoke the ShowDialog method which shows a modal dialog, but there is another subtle difference, whilst ChildWindow.Show returns immediately, with an event handler required to capture the modal dialog being closed, WPF’s Window.ShowDialog blocks until the dialog is closed.

So … each framework has different classes for modal dialogs, and different interfaces for each. How do we resolve these differences?

Early in this blog post we saw how the UserControl which is the entry point into our Silverlight application can be hosted in a WPF Window. The same approach can be used for modal dialogs. We can create our modal dialog as a UserControl:

<UserControl x:Class="ModalDialogDemo.ModalDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">    
    <Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
 
        <TextBlock Text="What is your favourite colour? " VerticalAlignment="Center"/>
        <TextBox x:Name="colourInput" Grid.Column="1" VerticalAlignment="Center" Width="80"/>
    </Grid>
</UserControl>

With the above control hosted in a ChildWindow or Window depending on the platform. The problem is, we cannot explicitly make reference to either of these types in our common code (i.e. the code shared by WPF / Silverlight via file linking). This problem can be solved by employing the Gang of Four Adapter pattern.

We define an interface that gives the functionality that we require for hosting our UserControl as a modal dialog:

/// <summary>
/// An interface which provides a host for some content which should be rendered
/// as a modal dialog
/// </summary>
public interface IModalDialogHost
{
    /// <summary>
    /// Gets or sets the content to host
    /// </summary>
    UserControl HostedContent { get; set; }
 
    /// <summary>
    /// Gets the dialog title
    /// </summary>
    string Title { set; }
 
    /// <summary>
    /// Gets the dialog result (i.e. OK, Cancel)
    /// </summary>
    bool? DialogResult { get; }
 
    /// <summary>
    /// Shows the dialog, invoking the given callback when it is closed
    /// </summary>
    void Show(DialogClosed closedCallback);        
}
 
/// <summary>
/// A callback which is invoked when a modal dialog is closed.
/// </summary>
public delegate void DialogClosed(IModalDialogHost host);

Within the Silverlight project we create a concrete implementation of this interface based on ChildWindow:

<controls:ChildWindow x:Class="ModalDialogDemo.ModalDialogHost"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:local="clr-namespace:ModalDialogDemo"
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <!-- the hosted content -->
        <ContentPresenter x:Name="contentHost"/>
 
        <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75"
                Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
        <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23"
                HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
    </Grid>
</controls:ChildWindow>

With the interface implemented in code-behind as follows:

/// <summary>
/// A Silverlight implementation of IModalDialogHost
/// </summary>
public partial class ModalDialogHost : ChildWindow, IModalDialogHost
{
    ...
 
    public UserControl HostedContent
    {
        get
        {
            return (UserControl)contentHost.Content;
        }
        set
        {
            contentHost.Content = value;
        }
    }
 
    public void Show(DialogClosed closedCallback)
    {
        Show();
 
        // handle the Closed event, invoking the callback provided by the client
        Closed += (s, e) =>
            {
                closedCallback(this);
            };
    }
 
    public new string Title
    {
        set { base.Title = value; }
    }
}

Within WPF we have a similar implementation based on Window:

<Window x:Class="ModalDialogDemo.ModalDialogHost"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        SizeToContent="WidthAndHeight"
        ShowInTaskbar="False">
    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <!-- the hosted content -->
        <ContentPresenter x:Name="contentHost" Margin="10"/>
 
        <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75"
                Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" />
        <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75"
                Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" />
    </Grid>
</Window>

Note that with WPF we have a few extra configuration options to consider, such as the ShowInTaskbar property. The code-behind again implements our adapter interface:

/// <summary>
/// A WPF implementation of IModalDialogHost
/// </summary>
public partial class ModalDialogHost : Window, IModalDialogHost
{
    ...
 
    public UserControl HostedContent
    {
        get
        {
            return (UserControl)contentHost.Content;
        }
        set
        {
            contentHost.Content = value;
        }
    }
 
    public void Show(DialogClosed closedCallback)
    {
        ShowDialog();
 
        // invoke the callback when the dialog is closed
        closedCallback(this);
    }
}

So, within each project we have a framework specific implementation of this host. This allows us to create modal dialogs from the common / core code as follows:

IModalDialogHost dlg = new ModalDialogHost();
dlg.Title = "Pick a Colour";
dlg.HostedContent = new ModalDialog();
dlg.Show(DialogClosedHandler);
 
...
 
private void DialogClosedHandler(IModalDialogHost dialogHost)
{
    string colour = ((ModalDialog)dialogHost.HostedContent).SelectedColour;
    resultTextBox.Text = colour;                        
}

Here is a Silverlight application with a dialog implemented using this hosting concept:

And here is a screenshot of the equivalent WPF application, where you can see the modal dialog is popped up as a window:

(You can download the sourcecode below if you want to have a go with the WPF app)

One final note … I have deliberately steered clear of the whole patterns business in this blog post. As you are probably aware, the Model-View-ViewModel (MVVM) pattern is very popular within Silverlight and WPF, and often other patterns such as Service Locator and Dependency Injection are thrown into the mix. However, the community has been struggling a little with how best to model modal dialog behaviours from within an MVVM ViewModel. Interestingly a couple of developers have supplied solutions on codeproject and personal blogs, both faced questions and even criticisms that their approaches were not correct and unit testable (one of the central tenets of MVVM) and quickly followed up with articles demonstrating that you could in fact unit test their code (published here and here)

Whilst the use of a pattern such as MVVM which enforces a strong separation of application logic from the view will certainly help to solve problems such as WPF / Silverlight framework differences, in this particular instance I wanted to show a simple technical solution rather than walk into the awaiting patterns minefield!

You can download the full sourcecode for this article here: ModalDialogDemo.zip

Regards, Colin E.

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
{
    /// <summary>
    /// Adapts a DependencyObject to provide methods required for generate
    /// a Linq To Tree API
    /// </summary>
    public class VisualTreeAdapter : ILinqTree<DependencyObject>
    {
        private DependencyObject _item;

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

        public IEnumerable<DependencyObject> 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
{
    /// <summary>
    /// Defines an interface that must be implemented to generate the LinqToTree methods
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface ILinqTree<T>
    {
        IEnumerable<T> Children();

        T Parent { get; }
    }

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

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

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

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

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

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

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

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

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

        /// <summary>
        /// Returns a collection of the sibling elements before this node, in document order.
        /// </summary>
        public static IEnumerable<DependencyObject> 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;
            }
        }

        /// <summary>
        /// Returns a collection of the after elements after this node, in document order.
        /// </summary>
        public static IEnumerable<DependencyObject> 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;
            }
        }

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

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

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

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

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

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

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

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

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

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

    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Regards, Colin E.