Змінити шаблон шаблону даних WPF для елемента ListBox, якщо вибрано


91

Мені потрібно змінити DataTemplate для елементів у ListBox залежно від того, вибраний елемент чи ні (відображається інша / більше інформації, коли вибрано).

Я не отримую подію GotFocus / LostFocus у самому верхньому елементі DataTemplate (StackPanel) при натисканні на відповідний елемент ListBox (лише за допомогою вкладки), і я втратив ідеї.

Відповіді:


184

Найпростіший спосіб зробити це - надати шаблон для "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}" />

1
Дякуємо, будь ласка, включіть <ListBox ItemContainerStyle = ”{StaticResource ContainerStyle}” ItemsSource = ”{Binding MyData}” /> у свою публікацію, щоб людям не потрібно було шукати у вашому блозі.
Shimmy Weitzhandler

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

1
Крім того, якщо ви хочете, щоб ваш новий ItemContainerStyle був сумісним із темами, вам доведеться базувати його на темі з теми. Для цього скористайтеся BasedOn="{StaticResource {x:Type ListBoxItem}}"ListBox. Це також стосується інших елементів керування, таких як TreeView.
Benny Jobigan

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 для пошуку списку перегляду

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.