Переключение ContentPresenter ListBoxItem на основе выбора - PullRequest
0 голосов
/ 06 июня 2011

Я пытаюсь отключить ContentPresenter объекта ListBoxItem, когда он выбран, при использовании нескольких шаблонов данных для представления различных типов данных.

Вот UserControl, который определяет ListBox внутри:

<UserControl x:Class="Homage.View.FilePanelView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:vw="clr-namespace:Homage.View"
         xmlns:vm="clr-namespace:Homage.ViewModel"
         xmlns:ctrl="clr-namespace:Homage.Controls"
         mc:Ignorable="d">

<UserControl.Resources>
    <DataTemplate DataType="{x:Type vm:SlugViewModel}">
        <vw:SlugView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}">
        <vw:HeaderSlugView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type vm:ContentSlugViewModel}">
        <vw:ContentSlugView />
    </DataTemplate>

    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border Name="SlugContainer" Background="Transparent" BorderBrush="Black" BorderThickness="1" CornerRadius="2" Margin="0,5,0,0" Padding="5">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>

                            <Label Grid.Row="0" Content="{Binding DisplayName}" />
                            <ContentPresenter Grid.Row="1" />

                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter TargetName="SlugContainer" Property="BorderThickness" Value="5" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

<Grid>
    <ListBox ItemsSource="{Binding Slugs}" Padding="5" />
</Grid>
</UserControl>

В зависимости от типа отображаемых данных (например, «Заголовок заголовка») определенный шаблон данных применяется к ListBoxItem. Это прекрасно работает, но я хочу настроить DataTemplate выбранного ListBoxItem на другой DataTemplate - опять же, в зависимости от отображаемого типа данных.

Цель состоит в том, что, поскольку каждый тип данных отличается, каждый будет иметь уникальный внешний вид, когда он не выбран, и получит уникальный набор параметров при выборе.

Если бы я мог заставить работать вышеперечисленное, это было бы здорово! Но я тоже хочу все усложнить ...

Хотя каждый тип данных имеет уникальные элементы управления, они также имеют общие элементы управления. Поэтому в идеале я хотел бы определить все общие элементы управления один раз, чтобы они отображались в одном и том же месте в ListBox.

<DataTemplate x:Key="CommonSelectedTemplate">
    <!-- common controls -->
    ...
    <DataTemplate x:Key="UniqueSelectedTemplate">
        <!-- all the unique controls -->
        <ContentPresenter /> 
    </DataTemplate>
    <!-- more common controls -->
    ...
</DataTemplate>

Если мне придется определять все общие вещи несколько раз (пока), я буду жить. =)

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 27 сентября 2011

Предположим, что у нас есть только два типа данных: Item1ViewModel и Item2ViewModel.Поэтому нам нужно 4 шаблона данных: 2 для общего состояния, 2 для выбранного состояния.

    <DataTemplate x:Key="Template1" DataType="local:Item1ViewModel">
        <TextBlock Text="{Binding Property1}" Foreground="Red" />
    </DataTemplate>
    <DataTemplate x:Key="Template2" DataType="local:Item2ViewModel">
        <TextBlock Text="{Binding Property2}" Foreground="Blue" />
    </DataTemplate>
    <DataTemplate x:Key="Template1Selected" DataType="local:Item1ViewModel">
        <TextBlock Text="{Binding Property1}" Background="Yellow" Foreground="Red" />
    </DataTemplate>
    <DataTemplate x:Key="Template2Selected" DataType="local:Item2ViewModel">
        <TextBlock Text="{Binding Property2}" Background="Yellow" Foreground="Blue" />
    </DataTemplate>

Для переключения содержимого между двумя шаблонами на основе разных типов я использую класс DataTemplateSelector:

public class SampleTemplateSelector:DataTemplateSelector
{
    public DataTemplate Type1Template { get; set; }
    public DataTemplate Type2Template { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is Item1ViewModel)
            return Type1Template;
        else if (item is Item2ViewModel)
            return Type2Template;

        return null;
    }
}

Нам нужны два экземпляра этого селектора: один для общего состояния и один для выбранного состояния.

    <local:SampleTemplateSelector x:Key="templateSelector" 
                                  Type1Template="{StaticResource Template1}"
                                  Type2Template="{StaticResource Template2}"/>
    <local:SampleTemplateSelector x:Key="selectedTemplateSelector" 
                                  Type1Template="{StaticResource Template1Selected}"
                                  Type2Template="{StaticResource Template2Selected}"/>

И после этого вы должны добавить этот код, который переключает два селектора:

    <DataTemplate x:Key="ListItemTemplate">
        <ContentControl x:Name="content"  Content="{Binding}" ContentTemplateSelector="{StaticResource templateSelector}" />
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
                <Setter TargetName="content" Property="ContentTemplateSelector" Value="{StaticResource selectedTemplateSelector}"/>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>

Вот и все, примените этот ItemTemplate к вашему ListBox без изменения ControlTemplate:

<ListBox ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ListItemTemplate}" />
...