Project Description
WPF enhancement allowing you to use your own business class structure to display complex hierarchies in a standard WPF TreeView control. The included data template resolver and converter allow you to specify which templates are used based on your class types.

Overview

The ComplexDataTemplates control library was designed to enhance how the Windows Presentation Foundation uses DataTemplates and HierarchicalDataTemplates to display hierarchical data in a TreeView or other similar controls. If you are tearing your hair out trying to get data templates and tree views to do something more than displaying the simplest of data hierarchies then this library is for you! Display TreeView nodes that contain multiple collections without having to rebuild your source data classes.


The following is an example of a TreeView control using this control library and standard xaml to display a multi-level dataset with multiple grouping nodes at several levels:

ScreenShot.png

The above data is based on the following sample type structure:

    public interface IItem
    {
        string Label { get; }
        string ToolTip { get; }
    }

    public class Item : IItem
    {
        public string Label { get; set; }

        public string ToolTip { get; set; }
    }

    public class ClassA : Item
    {
        public List<ClassB> ListOfClassB { get; private set; }
        public List<ClassC> ListOfClassC { get; private set; }

        public ClassA()
        {
            this.ListOfClassB = new List<ClassB>();
            this.ListOfClassC = new List<ClassC>();
        }
    }


    public class ClassB : Item
    {
    }

    public class ClassC : Item
    {
        public List<Item> Pickles { get; private set; }
        public List<Item> IceCream { get; private set; }

        public ClassC()
        {
            this.Pickles = new List<Item>();
            this.IceCream = new List<Item>();
        }
    }

ComplexGroupDataTemplateSelector

The ComplexGroupDataTemplateSelector enhances how DataTemplates are found in your application. In addition to being able to specify data templates for IEnumerable collections, the ComplexGroupDataTemplateSelector will also find a template based on a interface implemented by the data item or a base type found in the data item hierachy. Though data templates found in this manner are a little more expensive to perform than just a simple Type lookup, the ComplexGroupDataTemplateSelector caches it's resolutions to help reduce the overall performance impact. The template selector can be tuned for specify needs using a few properties. For more information please look here: ComplexGroupDataTemplateSelector.

One of the coolest features that the ComplexGroupDataTemplateSelector gives you is the ability to select a DataTemplate for an interface implemented by the data item or any base type of the data item. In the example shown above, all of the leaf nodes of the tree are displayed using one DataTemplate markup with it's DataType property set to DataType="{x:Type local:IItem}", since IItem is the interface implemented by all of the data items in the example, any data item not explicitly templated will get the default template for the IItem interface.

The following example shows were the ComplexGroupDataTemplateSelector can be used in your xaml:

<Window x:Class="ComplexDataTemplates.UnitTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ComplexDataTemplates.UnitTest"
    xmlns:complex="clr-namespace:DaisleyHarrison.WPF.ComplexDataTemplates;assembly=ComplexDataTemplates"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <complex:ComplexGroupDataTemplateSelector x:Key="complex-group-data-template-selector"/>
        ...
    <Window.Resources>
    <Grid>
        <TreeView x:Name="testTreeView" ItemTemplateSelector="{StaticResource complex-group-data-template-selector}">
            
        </TreeView>
    </Grid>
</Window>

ComplexGroupConverter

In order to support the use of multiple ItemsSource bindings we use a combination of the built-in type MultiBinding and the ComplexGroupConverter type found in this library. Note also that for this to work correctly the ItemControl must also use the ComplexGroupDataTemplateSelector.

In the example below you will find two HierarchicalDataTemplates that make use of MultiBinding and the ComplexGroupConverter. The first HierarchicalDataTemplate for DataType="{x:Type local:ClassA}" binds to two collections in ClassA "ListOfClassB" and "ListOfClassC". Since no ConverterParameter is defined the next level templates are found using the keys: "IEnumerable[ClassB]" and "IEnumerable[ClassC]" which are automatically generated by the ComplexGroupDataTemplateSelector. For more control of the templates used on the next level and to support more than one collection of the same element type, the next HierarchicalDataTemplate for DataType="{x:Type local:ClassC}" also use a ConverterParameter to specific the names of the DataTemplates to be used on the next level. So support for the "Pickles" collection binding will look for a DataTemplate with x:Key="Pickles-Template". Support for the "IceCream" collection binding will look for a DataTemplate with x:Key="IceCream-Template"

For more information please look here: ComplexGroupConverter

The following example shows were the ComplexGroupConverter can be used in your xaml:

<Window x:Class="ComplexDataTemplates.UnitTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ComplexDataTemplates.UnitTest"
    xmlns:complex="clr-namespace:DaisleyHarrison.WPF.ComplexDataTemplates;assembly=ComplexDataTemplates"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <complex:ComplexGroupDataTemplateSelector x:Key="complex-group-data-template-selector"/>
        <complex:ComplexGroupConverter x:Key="complex-group-converter"/>
        <HierarchicalDataTemplate DataType="{x:Type local:ClassA}">
            <HierarchicalDataTemplate.ItemsSource>
                <MultiBinding Converter="{StaticResource complex-group-converter}">
                    <Binding Path="ListOfClassB"/>
                    <Binding Path="ListOfClassC"/>
                </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/classA.jpg" VerticalAlignment="Center"  Margin="0,5,0,5"/>
                <TextBlock Text="{Binding Path=Label}" ToolTip="{Binding Path=ToolTip}" VerticalAlignment="Center"  Margin="5,0,0,0"/>
            </StackPanel>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate x:Key="IEnumerable[ClassB]" ItemsSource="{Binding Path=.}">
            <TextBlock>List of Class Bs</TextBlock>
        </HierarchicalDataTemplate>
         ...
        <HierarchicalDataTemplate DataType="{x:Type local:ClassC}">
            <HierarchicalDataTemplate.ItemsSource>
                <MultiBinding Converter="{StaticResource complex-group-converter}" ConverterParameter="Pickles-Template,IceCream-Template">
                    <Binding Path="Pickles"/>
                    <Binding Path="IceCream"/>
                </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
            <StackPanel Orientation="Horizontal">
                <Image Source="Images/classC.jpg" VerticalAlignment="Center" Margin="0,5,0,5"/>
                <TextBlock  VerticalAlignment="Center"  Margin="5,0,0,0">Class C:</TextBlock>
                <TextBlock Text="{Binding Path=Label}" ToolTip="{Binding Path=ToolTip}"  VerticalAlignment="Center"  Margin="5,0,0,0"/>
            </StackPanel>
        </HierarchicalDataTemplate>

        ...
    <Window.Resources>
    <Grid>
        <TreeView x:Name="testTreeView" ItemTemplateSelector="{StaticResource complex-group-data-template-selector}">
            
        </TreeView>
    </Grid>
</Window>

A complete working example is available in the downloadable source that can be found here: Released Files

Last edited Dec 2, 2008 at 9:19 PM by aarondh, version 31