mightymaus mightymaus - 3 months ago 49
C# Question

Bind ListBox item background & selection colors in WPF

I have a list where the background color of each item should depend on two things: the selection state and a boolean property in the data context. I've figured out how to bind the background color, but as soon as I select the list item my custom background disappears.

The end result would ideally be (depending on the selection state) a shade of green if the data context boolean is true or a shade of red if it's false.

MainWindow.xaml:

<ListBox x:Name="CrewList" ItemsSource="{Binding CrewList}" SelectedItem="{Binding SelectedCrew}" Style="{StaticResource EventOverviewListBox}" Grid.Column="1" Grid.Row="0">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Data.IsValid}" Value="true">
<Setter Property="Background" Value="{StaticResource StatusValid}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Data.IsValid}" Value="false">
<Setter Property="Background" Value="{StaticResource StatusInvalid}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,10,10,10" KeyboardNavigation.IsTabStop="False">
<TextBlock Text="{Binding Lane}" Margin="0,0,20,0" FontSize="20" />
<TextBlock Text="{Binding ClubName}" Foreground="Black" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>


App.xaml:

<SolidColorBrush x:Key="StatusValid">LawnGreen</SolidColorBrush>
<SolidColorBrush x:Key="StatusInvalid">Red</SolidColorBrush>
<Style x:Key="EventOverviewListBox" TargetType="ListBox">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Teal"/>
</Style>
<Style x:Key="EventOverviewListBoxItem" TargetType="ListBoxItem">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>


I've searched and searched but haven't found anything in the last couple of hours, so I'm hoping someone else knows of a way.

Thanks!

Answer

I'm assuming that by "selection state" you mean if the item is selected or not.

The ListBoxItem has a ControlTemplate with triggers that takes precedence over the triggers. You need to create your own ControlTemplate for the ListBoxItem style. Also, use a MultiDataTrigger.

Like this:

<Style TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Border Name="BorderWrap">
                    <ContentPresenter />
                </Border>
                <ControlTemplate.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self},Path=IsSelected}" Value="True" />
                            <Condition Binding="{Binding Data.IsValid}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <MultiDataTrigger.Setters>
                            <Setter TargetName="BorderWrap" Property="Background" Value="{StaticResource StatusValid}"/>
                        </MultiDataTrigger.Setters>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Self},Path=IsSelected}" Value="True" />
                            <Condition Binding="{Binding Data.IsValid}" Value="False" />
                        </MultiDataTrigger.Conditions>
                        <MultiDataTrigger.Setters>
                            <Setter TargetName="BorderWrap" Property="Background" Value="{StaticResource StatusInvalid}"/>
                        <MultiDataTrigger.Setters>
                    </MultiDataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>