Измените WPF DataTemplate для элемента ListBox, если он выбран

Мне нужно изменить DataTemplate для элементов в ListBox в зависимости от того, выбран ли элемент или нет (отображается различная/дополнительная информация при выборе).

Я не получаю событие GotFocus/LostFocus в самом верхнем элементе DataTemplate (StackPanel) при нажатии на элемент списка ListBox (только через tabbing), и у меня нет идей.

Ответ 1

Самый простой способ сделать это - предоставить шаблон для свойства "ItemContainerStyle" и НЕ "ItemTemplate". В приведенном ниже коде я создаю 2 шаблона данных: один для "невыбранный" и один для "выбранных" состояний. Затем я создаю шаблон для "ItemContainerStyle", который является фактическим "ListBoxItem", который содержит элемент. Я установил значение по умолчанию "ContentTemplate" в состояние "Unselected", а затем предоставил триггер, который меняет шаблон, когда свойство IsSelected истинно. (Примечание. Я устанавливаю свойство "ItemsSource" в коде позади списка строк для простоты)

<Window.Resources>

<DataTemplate x:Key="ItemTemplate">
    <TextBlock Text="{Binding}" Foreground="Red" />
</DataTemplate>

<DataTemplate x:Key="SelectedTemplate">
    <TextBlock Text="{Binding}" Foreground="White" />
</DataTemplate>

<Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
    <Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
        </Trigger>
    </Style.Triggers>
</Style>

</Window.Resources>
<ListBox x:Name="lstItems" ItemContainerStyle="{StaticResource ContainerStyle}" />

Ответ 2

Следует также отметить, что стекная панель не является допустимой, поэтому она никогда не будет получать фокус (установите Focusable = True, если вы/действительно/хотите, чтобы она сфокусировалась). Тем не менее, ключ для запоминания в таких сценариях, как это, заключается в том, что Stackpanel - это дочерний TreeViewItem, который в этом случае является ItemContainer. Как утверждает Мика, тонкая настройка стиля контейнера - хороший подход.

Возможно, вы могли бы сделать это с помощью DataTemplates и таких вещей, как datatriggers, которые будут использовать расширение разметки RelativeSouce для поиска listviewitem

Ответ 3

Чтобы установить стиль, когда элемент выбран или не все, что вам нужно сделать, это восстановить родительский элемент ListBoxItem в <DataTemplate> и изменить стиль запуска при изменении его IsSelected. Например, приведенный ниже код создаст TextBlock со значением по умолчанию Foreground color green. Теперь, если элемент будет выбран, шрифт превратится в красный, и когда мышь закончится, элемент станет желтым. Таким образом, вам не нужно указывать отдельные шаблоны данных, как предложено в других ответах для каждого состояния, которое вы хотите слегка изменить.

<DataTemplate x:Key="SimpleDataTemplate">
    <TextBlock Text="{Binding}">
        <TextBlock.Style>
            <Style>
                <Setter Property="TextBlock.Foreground" Value="Green"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={
                        RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem }}}"
                                 Value="True">
                        <Setter Property="TextBlock.Foreground" Value="Red"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=IsMouseOver, RelativeSource={
                        RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem }}}"
                                 Value="True">
                        <Setter Property="TextBlock.Foreground" Value="Yellow"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</DataTemplate>