Выбор шаблона на основе данных в WPF

У меня есть этот простой пример XAML:

<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>

Он отображает мои элементы в наблюдаемой коллекции в стиле MVVM. Каждый элемент имеет свое горизонтальное положение в свойстве. У каждого элемента также есть свойство IsSpecial, которое сообщает, хочет ли он быть отрисован каким-то особым образом. Я хочу, чтобы обычные элементы (IsSpecial=false) отображались как красные квадраты (уже в коде), а специальные элементы — как синие круги со «специальным» текстом внутри.

Чего я не знаю, так это того, как настроить код XAML для выбора шаблона для элементов. Есть ли способ сделать это без кодирования моего собственного ItemTemplateSelector? Будет ли он по-прежнему работать с позиционированием холста на основе привязки. Я думаю, что решение состоит в том, чтобы извлечь шаблон элемента в отдельный шаблон, создать еще один шаблон для специальных элементов и затем как-то поиграться с триггерами ... но это не очень легко для меня, так как я новичок в WPF на данный момент.

Другое дело, что мне очень не нравится, как позиция передается элементам. Есть ли другой способ?

Есть ли другие рекомендации по улучшению кода?


person Kuba    schedule 29.06.2009    source источник


Ответы (1)


Я сам решил :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>

Но все же, есть мысли об альтернативах или улучшениях?

person Kuba    schedule 30.06.2009