Home > View Post

Different DataTemplates for different data

In yesterday's post Different DataTemplates for different types we looked at how you could have WPF dynamically select a DataTemplate based on the type of content being presented.

Perhaps a more likely scenarios is that you'd like to select a different DataTemplate based on some property of the bound content.

Since I like to use Xaml only for most of my examples we're going to use the ObjectDataProvider to fetch us some interesting data. I've blogged about him before: Xaml ObjectDataProvider. They really did think of everything.

We're going to use the static GetProcesses method of the System.Diagnostics.Process type to fetch all the running processes and store them in a resource, like so:

<ObjectDataProvider MethodName="GetProcesses" ObjectType="{x:Type diag:Process}" x:Key="processes" />

Note we needed to add a reference for the xml namespace diag which points to the System.Diagnostics namespace in the System.dll ( xmlns:diag="clr-namespace:System.Diagnostics;assembly=System" ).

Next, we'll bind our listbox to the processes:

<ListBox ItemsSource="{Binding Source={StaticResource processes}, Path=.}" IsSynchronizedWithCurrentItem="true" DisplayMemberPath="ProcessName" />

And now we'll add a ContentControl to show the currently selected process (much like yesterday's example).

<ContentControl Content="{Binding Source={StaticResource processes}, Path=/}" />

At last, something interesting...

Let's use a style to set the ContentTemplate of the content control to something more interesting by adding a DataTemplate to the resources of the page/window:

<DataTemplate x:Key="default">
    <Border BorderBrush="Purple" BorderThickness="2" CornerRadius="5">
        <TextBlock Foreground="Purple" FontWeight="Bold" Padding="5">
            <Run Text="(" />
                <TextBlock Text="{Binding Id}" />
            <Run Text=") "/>
            <TextBlock Text="{Binding ProcessName}" />
        </TextBlock>
    </Border>
</DataTemplate>

Next, we apply the style:

<ContentControl Content="{Binding Source={StaticResource processes}, Path=/}">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="ContentTemplate" Value="{StaticResource default}"/>
        </Style>
    </ContentControl.Style>
</ContentControl>

Default Template

Nice.

Now, imagine we want to change the template used by the content control based on some property of the bound Process. For example, we want to display an entirely different template for the Idle process (where Id==0).

<DataTemplate x:Key="idle">
    <Border BorderBrush="Green" BorderThickness="2" Background="LightGreen">
        <TextBlock Padding="20">This is the Idle process.</TextBlock>
    </Border>
</DataTemplate>

Let's have another template (called 'high') for high priority processes (where BasePriority==13).

<DataTemplate x:Key="high">
    <Border BorderBrush="Red" Background="Pink" BorderThickness="2" CornerRadius="10">
        <StackPanel>
            <TextBlock FontWeight="Bold" Foreground="Red">THIS IS A HIGH PRIORITY PROCESS</TextBlock>
            <ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource default}" HorizontalAlignment="Center" />
        </StackPanel>
    </Border>
</DataTemplate>

Note how we've cunningly reused another DataTemplate within this one. Finally, we need to use some DataTriggers in our ContentControl's style to apply the templates as per our rules.

<ContentControl Content="{Binding Source={StaticResource processes}, Path=/}">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Setter Property="ContentTemplate" Value="{StaticResource default}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Source={StaticResource processes}, Path=/Id}" Value="0">
                    <Setter Property="ContentTemplate" Value="{StaticResource idle}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding Source={StaticResource processes}, Path=/BasePriority}" Value="13">
                    <Setter Property="ContentTemplate" Value="{StaticResource high}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>

And here's the Idle template in action...

Idle Template

... and the High template...

High Template

Easy peasy. Download the full xaml source.

Tags: WPF

 
Josh Post By Josh Twist
11:27 AM
20 Feb 2008

» Next Post: Defense in depth: UI Security is never enough
« Previous Post: Different DataTemplates for different types

Comments are closed for this post.

© 2005 - 2017 Josh Twist - All Rights Reserved.