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:

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