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


91

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

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

Ответы:


184

Самый простой способ сделать это - предоставить шаблон для свойства «ItemContainerStyle», а НЕ для свойства «ItemTemplate». В приведенном ниже коде я создаю 2 шаблона данных: один для «невыбранных» и один для «выбранных» состояний. Затем я создаю шаблон для «ItemContainerStyle», который является фактическим «ListBoxItem», содержащим элемент. Я установил для параметра ContentTemplate по умолчанию значение «Unselected», а затем предоставил триггер, который заменяет шаблон, когда свойство «IsSelected» имеет значение true. (Примечание: для простоты я устанавливаю свойство «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}" />

1
Спасибо, пожалуйста, включите <ListBox ItemContainerStyle = ”{StaticResource ContainerStyle}” ItemsSource = ”{Binding MyData}” /> в свое сообщение, чтобы людям не приходилось искать в вашем блоге.
Шимми Вайцхандлер,

2
Одна из проблем, с которыми я столкнулся при установке ContainerStyle ListBox, заключается в том, что он вызывает несовместимость с темами. Я использовал ваш подход, но когда я применил тему из набора WPF Futures, ListBoxItems имел стиль по умолчанию вместо стиля темы. В моем случае черный текст на черном фоне и вообще безобразие. Я все еще ищу другой подход, возможно, с использованием триггеров DataTemplate.
Бенни Джобиган 01

1
Кроме того, если вы хотите, чтобы ваш новый ItemContainerStyle был совместим с темами, вы должны основывать его на элементе из темы. Для этого используйте BasedOn="{StaticResource {x:Type ListBoxItem}}"ListBox. Это также относится к другим элементам управления, таким как TreeView.
Бенни Джобиган

5
При использовании этого я обнаружил, что мне пришлось объявить DataTemplates над стилем в разделе ресурсов, чтобы не получить скрытых ошибок XAML. Просто предупреждаю об этом.
Роб Перкинс,

8

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

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

1
Как я уже писал в вопросе, я на самом деле показываю больше информации, если выбрано (« отображение другой / дополнительной информации при выборе »). Тем не менее, если бы это можно было заставить работать с переключением видимости некоторых элементов (включая то, занимают ли они размер), это было бы жизнеспособным решением. Однако некоторое время не работал с WPF.
Дэниел Бек

6

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.