Search code examples
wpfxamlwpf-style

Change Selection Color of ListBoxItem in WPF


Sorry that my question is redundant for instance with these ones:

but for whatever reason neither changing the ItemContainerStyle, nor overriding the SystemColors works for me. Can someone tell me what I have to change in this XAML code to change the background color of selected ListBoxItems (or more precisely the ItemsContainer around them) to red? All the other colors that I set are assigned correctly.

<ListBox>
    <ListBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightColorKey}" Color="Red" />
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Red" />
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey }" Color="Red" />
    </ListBox.Resources>

    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Foreground" Value="HotPink"/>
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="Margin" Value="2"/>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Foreground" Value="Green"/>
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Foreground" Value="Green"/>
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>

    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>

    <ListBoxItem>A</ListBoxItem>
    <ListBoxItem>B</ListBoxItem>
    <ListBoxItem>C</ListBoxItem>
    <ListBoxItem>D</ListBoxItem>
</ListBox>

Solution

  • Both approaches do not work because:

    • The default control templates may not necessarily use the system colors.
    • The default control template triggers take precedence over your style setters.

    You have to extract the default style and control template e.g. by using Visual Studio or Blend in order to have a working base to start from. Adapt the colors in the styles an control template triggers.

    <SolidColorBrush x:Key="Item.MouseOver.Background"
                     Color="#1F26A0DA" />
    <SolidColorBrush x:Key="Item.MouseOver.Border"
                     Color="#a826A0Da" />
    <SolidColorBrush x:Key="Item.SelectedActive.Background"
                     Color="#3D26A0DA" />
    <SolidColorBrush x:Key="Item.SelectedActive.Border"
                     Color="#FF26A0DA" />
    <SolidColorBrush x:Key="Item.SelectedInactive.Background"
                     Color="#3DDADADA" />
    <SolidColorBrush x:Key="Item.SelectedInactive.Border"
                     Color="#FFDADADA" />
    <Style x:Key="FocusVisual">
       <Setter Property="Control.Template">
          <Setter.Value>
             <ControlTemplate>
                <Rectangle Margin="2"
                           StrokeDashArray="1 2"
                           SnapsToDevicePixels="true"
                           StrokeThickness="1"
                           Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
             </ControlTemplate>
          </Setter.Value>
       </Setter>
    </Style>
    <Style x:Key="ListBoxItemStyle"
           TargetType="{x:Type ListBoxItem}">
       <Setter Property="SnapsToDevicePixels"
               Value="True" />
       <Setter Property="Padding"
               Value="4,1" />
       <Setter Property="HorizontalContentAlignment"
               Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
       <Setter Property="VerticalContentAlignment"
               Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
       <Setter Property="Background"
               Value="Transparent" />
       <Setter Property="BorderBrush"
               Value="Transparent" />
       <Setter Property="BorderThickness"
               Value="1" />
       <Setter Property="FocusVisualStyle"
               Value="{StaticResource FocusVisual}" />
       <Setter Property="Template">
          <Setter.Value>
             <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <Border x:Name="Bd"
                        Background="{TemplateBinding Background}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        Padding="{TemplateBinding Padding}"
                        SnapsToDevicePixels="true">
                   <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                     SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                     VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
                <ControlTemplate.Triggers>
                   <MultiTrigger>
                      <MultiTrigger.Conditions>
                         <Condition Property="IsMouseOver"
                                    Value="True" />
                      </MultiTrigger.Conditions>
                      <Setter Property="Background"
                              TargetName="Bd"
                              Value="{StaticResource Item.MouseOver.Background}" />
                      <Setter Property="BorderBrush"
                              TargetName="Bd"
                              Value="{StaticResource Item.MouseOver.Border}" />
                   </MultiTrigger>
                   <MultiTrigger>
                      <MultiTrigger.Conditions>
                         <Condition Property="Selector.IsSelectionActive"
                                    Value="False" />
                         <Condition Property="IsSelected"
                                    Value="True" />
                      </MultiTrigger.Conditions>
                      <Setter Property="Background"
                              TargetName="Bd"
                              Value="{StaticResource Item.SelectedInactive.Background}" />
                      <Setter Property="BorderBrush"
                              TargetName="Bd"
                              Value="{StaticResource Item.SelectedInactive.Border}" />
                   </MultiTrigger>
                   <MultiTrigger>
                      <MultiTrigger.Conditions>
                         <Condition Property="Selector.IsSelectionActive"
                                    Value="True" />
                         <Condition Property="IsSelected"
                                    Value="True" />
                      </MultiTrigger.Conditions>
                      <Setter Property="Background"
                              TargetName="Bd"
                              Value="{StaticResource Item.SelectedActive.Background}" />
                      <Setter Property="BorderBrush"
                              TargetName="Bd"
                              Value="{StaticResource Item.SelectedActive.Border}" />
                   </MultiTrigger>
                   <Trigger Property="IsEnabled"
                            Value="False">
                      <Setter Property="TextElement.Foreground"
                              TargetName="Bd"
                              Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                   </Trigger>
                </ControlTemplate.Triggers>
             </ControlTemplate>
          </Setter.Value>
       </Setter>
    </Style>
    

    Then use the style in your ListBox by explicitly referencing it or make it an implicit style style by omitting the x:Key, so it will be applied to all ListBoxItems in scope.

    <ListBox ItemContainerStyle="{StaticResource ListBoxItemStyle}">