Change WPF DataTemplate for ListBox item if selected

.NetWpf

.Net Problem Overview


I need to change the DataTemplate for items in a ListBox depending on whether the item is selected or not (displaying different/more information when selected).

I don't get a GotFocus/LostFocus event on the top-most element in the DataTemplate (a StackPanel) when clicking the ListBox item in question (only through tabbing), and I'm out of ideas.

.Net Solutions


Solution 1 - .Net

The easiest way to do this is to supply a template for the "ItemContainerStyle" and NOT the "ItemTemplate" property. In the code below I create 2 data templates: one for the "unselected" and one for the "selected" states. I then create a template for the "ItemContainerStyle" which is the actual "ListBoxItem" that contains the item. I set the default "ContentTemplate" to the "Unselected" state, and then supply a trigger that swaps out the template when the "IsSelected" property is true. (Note: I am setting the "ItemsSource" property in the code behind to a list of strings for simplicity)

<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}" />

Solution 2 - .Net

To set the style when the item is selected or not all you need to do is to retrieve the ListBoxItem parent in your <DataTemplate> and trigger style changes when its IsSelected changes. For example the code below will create a TextBlock with default Foreground color green. Now if the item gets selected the font will turn red and when the mouse is over the item will turn yellow. That way you don't need to specify separate data templates as suggested in other answers for every state you'd like to slightly change.

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

Solution 3 - .Net

It should also be noted, that the stackpanel isn't focuable, so it's never going to get focus (set Focusable=True if you /really/ want it focused). However, the key to remember in scenarios like this is that the Stackpanel is child of the TreeViewItem, which is the ItemContainer in this case. As Micah suggests, tweaking the itemcontainerstyle is a good approach.

You could probably do it using DataTemplates, and things such as datatriggers which would use the RelativeSouce markup extension to look for the listviewitem

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaniel BeckView Question on Stackoverflow
Solution 1 - .NetMicahView Answer on Stackoverflow
Solution 2 - .NetDarien PardinasView Answer on Stackoverflow
Solution 3 - .NetDominic HoptonView Answer on Stackoverflow