ITM .NET Utils - Type dependent WPF Data Template Selector

by pawel.mieten 14. April 2009 09:03

When you design user interface in WPF there is often a necessity to change some view depending on some condition. Of course in some case you can use triggers, but if you want to use different templates depending on the type of the underlying object, System.Windows.Controls.DataTemplateSelector is the right choice.

You have to create a new class that inherits from System.Windows.Controls.DataTemplateSelector. Then you should override SelectTemplate method which is responsible for returning a correct DataTemplate.

Below is an example implementation of DataTemplateSelector, which holds a collection of DataTemplates objects. Each DataTemplate has a DataType Property, which indicates the object type the template is responsible for.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
 
namespace Itm.Windows.Controls
{
    /// <summary>
    /// Choses a approperiate data template for the object from the internal collection.
    /// </summary>
    [ContentProperty("Templates")]
    public class DataTypeTemplateSelector : DataTemplateSelector
    {
        #region Private Static Fields
        /// <summary>
        /// Collection of available data templates.
        /// </summary>
        private readonly List<DataTemplate> templates = new List<DataTemplate>();
        #endregion
 
        #region Public Properties
        /// <summary>
        /// Gets the collection of available data templates.
        /// </summary>
        /// <value>The collection of available data templates.</value>
        public List<DataTemplate> Templates
        {
            get
            {
                return templates;
            }
        }
        #endregion
 
        #region Public Methods
        /// <summary>
        /// When overridden in a derived class, returns a <see cref="DataTemplate"/> based on custom logic.
        /// </summary>
        /// <param name="item">The data object for which to select the template.</param>
        /// <param name="container">The data-bound object.</param>
        /// <returns>
        /// Returns a <see cref="DataTemplate"/> or null. The default value is null.
        /// </returns>
        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item != null)
            {
                Type type = item.GetType();
 
                DataTemplate dataTemplate = templates.FirstOrDefault(d => d.DataType == type);
 
                if (dataTemplate != null)
                {
                    return dataTemplate;
                }
            }
 
            return base.SelectTemplate(item, container);
        }
        #endregion
    }
}

After you implemented the DataTemplateSelector class it is ready to be used right away.

Below is the XAML code example of Template Selector utilization. The example is based on a ListView which ItemsSource is bound to the list containing two types of objects: Order and Message. Inside the DataTypeTemplateSelector I defined two data templates, one for each item type.

<DataTemplate DataType="{x:Type loc:Order}"> -This data template is used for items which are Order.

<DataTemplate DataType="{x:Type loc:Message}"> -This data template is used for items which are Message.

<Window x:Class="DataTemplateSelectorBlog.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:loc="clr-namespace:DataTemplateSelectorBlog"
        xmlns:itm="clr-namespace:Itm.Windows.Controls"
        Title="Window1"
        Height="300"
        Width="300"
        x:Name="MineWindow">
    <Grid>
        <ListView  ItemsSource="{Binding ElementName=MineWindow, Path=Items}">
            <ListView.ItemTemplateSelector>
                <itm:DataTypeTemplateSelector>
                    <DataTemplate DataType="{x:Type loc:Order}">
                        <GroupBox Header="Order"
                                  BorderBrush="Red">
                            <StackPanel>
                                <TextBlock Foreground="Blue"
                                           Text="{Binding Path=Client, StringFormat=Client: {0} }"></TextBlock>
                                <TextBlock Foreground="Black"
                                           Text="{Binding Path=Product}"></TextBlock>
                                <TextBlock Foreground="DarkGray"
                                           Text="{Binding Path=Price}"></TextBlock>
                            </StackPanel>
                        </GroupBox>
                    </DataTemplate>
                    <DataTemplate DataType="{x:Type loc:Message}">
                        <GroupBox Header="Message">
                            <StackPanel>
                                <TextBlock Foreground="Blue"
                                           Text="{Binding Path=From, StringFormat=From: {0} }"></TextBlock>
                                <TextBlock Foreground="DarkGray"
                                           Text="{Binding Path=Text}"></TextBlock>
                            </StackPanel>
                        </GroupBox>
                    </DataTemplate>
                </itm:DataTypeTemplateSelector>
            </ListView.ItemTemplateSelector>
        </ListView>
 
    </Grid>
</Window>

The visual representation of two Message objects and one Order object

image

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

.NET

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen