views:

548

answers:

2

I have this simple XAML example:

<Window x:Class="DynTemplateTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>
        <DataTemplate x:Key="ItemTemplate">
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Rectangle Width="30" Height="30" Fill="Red"></Rectangle>                        
                    </DataTemplate>
                </ItemsControl.ItemTemplate>  
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style>
                        <Setter Property="Canvas.Left" Value="{Binding Position}"></Setter>
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </DataTemplate>
    </Window.Resources>

    <DockPanel LastChildFill="True">
        <ContentPresenter
            Content="{Binding Path=Items}"
            ContentTemplate="{StaticResource ItemTemplate}"
            >
        </ContentPresenter>
    </DockPanel>

</Window>

It is rendering my items in the observable collection in MVVM style. Each item is having its horizontal position in a property. Each item also has a property IsSpecial which tells if it wants to be rendered in some special way. I want ordinary items (IsSpecial=false) render as red squares (already in the code) and special items as blue circles with "special" text inside.

What I do not know is how to adjust the XAML code to do the template selection for the items. Is there a way to do that without coding my own ItemTemplateSelector? Will it still work with the canvas positioning based on binding. I think that the solution is to extract the item template to a separate template, create one more template for special items and then somehow play with triggers ... but it is not very easy for me as I am a WPF beginner at the moment.

The other thing is that I quite dislike the way how the Position is passed to the items. Is there some other way?

Are there any other recommendations how to improve the code?

A: 

I solved it myself :D

<Window x:Class="DynTemplateTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>
        <DataTemplate x:Key="NormalItem">
            <Rectangle Width="30" Height="30" Fill="Red"></Rectangle>                        
        </DataTemplate>
        <DataTemplate x:Key="SpecialItem">
            <Rectangle Width="30" Height="30" Fill="Red"></Rectangle>                        
        </DataTemplate>
        <DataTemplate x:Key="ItemTemplate">
            <ItemsControl ItemsSource="{Binding}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentControl Content="{Binding}" ContentTemplate="{StaticResource NormalItem}" x:Name="ItemsContentControl" />
                        <DataTemplate.Triggers>
                            <DataTrigger Binding="{Binding Path=IsSpecial}" Value="true">
                                <Setter TargetName="ItemsContentControl" Property="ContentTemplate" Value="{StaticResource SpecialItem}" />
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>  
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style>
                        <Setter Property="Canvas.Left" Value="{Binding Position}" />
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </DataTemplate>
    </Window.Resources>

    <DockPanel LastChildFill="True">
        <ContentPresenter
            Content="{Binding Path=Items}"
            ContentTemplate="{StaticResource ItemTemplate}"
            >
        </ContentPresenter>
    </DockPanel>

</Window>

But still, any thoughts on alternatives or improvements?

Kuba
A: 

really nice. Well done, you have saved me a big headache. I needed a "Pivot" component, but I couldn't figure out how to position the cells in my Grid. Now I know.

ZeePrime