67

I'm creating a WPF application where several ListView selections are made in a row (similar to the iTunes browser). The problem is that the default inactive selection color is too light. (see below) Default inactive selection color (too light)

How can I change this color so my inactive listview looks like this? (see below) Inactive and active selection colors the same

Solution

Override the default SystemColor with a Style like so:

<Style TargetType="ListViewItem">
    <Style.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="{x:Static SystemColors.HighlightColor}"/>
    </Style.Resources>
</Style>
Joseph Sturtevant
  • 13,194
  • 12
  • 76
  • 90

8 Answers8

65

Changing SystemColors.ControlBrushKey did not work for me, I had to change SystemColors.InactiveSelectionHighlightBrushKey

So instead of:

<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Red" />

I had to use:

<SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Red"/>
Mafii
  • 7,227
  • 1
  • 35
  • 55
user672951
  • 731
  • 6
  • 4
  • I also had to change this value, the ControlBrushKey was not changing the color. However the color I enter is still getting a another color applied on top of it, so my Blue is looking more purple. Did this happen to you? – Caleb S Mar 06 '13 at 01:19
  • 2
    I wish I could upvote this answer more than once, as I've tried to resolve this issue a number of times . I am also using .NET 4.5 and have tried all the other answers without success. – Zev Spitz May 08 '13 at 14:45
  • This is what I used before I had to work on a .NET 4 project... I had to implement a style similar to the Solution answer for .NET 4 for my DataGridRow so that it would be easier to work with data (knowing easily what was selected). – B.K. Dec 31 '13 at 02:05
  • 2
    in .net 4.5 FrameworkCompatibilityPreferences.AreInactiveSelectionHighlightBrushKeysSupported field controls which color is used for the highlight. – John Melville Jan 09 '14 at 04:36
  • `SystemColors.ControlBrushKey` Worked for me, Thank You. – SkyDancer Dec 09 '21 at 15:32
  • WPF on net6, had to use `SystemColors.InactiveSelectionHighlightBrushKey` and `SystemColors.InactiveSelectionHighlightTextBrushKey` – Viktor Feb 14 '23 at 09:51
60

The ListBox template uses a system color called ControlBrush to set the inactive highlight color. Therefore, you can just override that color:

<ListBox>
    <ListBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}">Red</SolidColorBrush>
    </ListBox.Resources>
</ListBox>
Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • 4
    There issues with doing it this way. It doesn't allow you to skin the app, and if you go and change the system colors by changing your Windows Theme, it will revert back – Micah Dec 19 '08 at 20:45
  • Doesn't allow you to skin the app? How so? Just look up a resource for the color instead of hard-coding as red. And I just tested changing the theme with a test harness running, and it worked perfectly. Please clarify. – Kent Boogaart Dec 19 '08 at 20:52
  • That's suprising. What happens if you put other listboxes on a form that you don't want styled that way? – Micah Dec 19 '08 at 21:29
  • The resource is defined at the ListBox level, so it only affects that ListBox. – Kent Boogaart Dec 19 '08 at 21:37
  • 1
    What's actually happening is you are overriding the style key for all objects that use it. – Micah Dec 19 '08 at 21:39
  • 1
    It's a resource so subject to the normal rules of resource lookup. Micah, try it yourself. Put two ListBoxes in a Window - one with the resource override and one without. The color change only affects the one with the resource override. – Kent Boogaart Dec 19 '08 at 22:27
  • Thanks for the comments, both of you. I agree that there are potential issues with this solution (variable Windows Themes, etc.), but in this case I want the inactive highlighting to be the same color as the active highlighting, so this solution is exactly what I'm looking for. – Joseph Sturtevant Dec 19 '08 at 23:54
  • I have exactly same problem. But my font color needs to be white. At moment it is set to white, but it's gets override by this resource to black. Any ideas how to change that? Thank You. – Daniil Harik Apr 27 '09 at 11:05
  • 6
    For .NET 4.5, it looks like they changed the key -- see @user672951 answer below. – Ed Bayiates Jun 21 '13 at 21:01
  • This is a BAD idea -- DO NOT DO THIS -- for users with visual effects turned off, this will mess up a lot of things -- the scroll bars and buttons will change to become the current highlight color (this is blue by default -- so your inner buttons and ListView scrollbars turn blue, very bad!). [To see what I mean, try this hack out on the "Windows Classic" theme, since it has all the visual effects disabled.] Please see the popular answer here for the CORRECT way to do this: https://stackoverflow.com/questions/1462232/selected-item-loses-style-when-focus-moved-out-in-wpf-listbox – BrainSlugs83 Aug 28 '14 at 04:31
20

The answer will in some cases solve the problem, but is not ideal as it breaks when the control is disabled/readonly and it also overrides the color schemes, rather than taking advantage of them. My suggestion is to add the following in the ListBox tags instead:

<ListBox....>
    <ListBox.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <Border Name="Border" Padding="2" SnapsToDevicePixels="true">
                                <ContentPresenter />
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsSelected" Value="true">
                                    <Setter TargetName="Border" Property="Background"
                                            Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
        </Style>
    </ListBox.Resources>
</ListBox>

What this will do is set the Highlight background color on the list box item whenever it is selected (regardless of the control state).

My answer is based on help from the answer already given, along with the following blog: http://blogs.vbcity.com/xtab/archive/2009/06/29/9344.aspx

Thies
  • 4,101
  • 2
  • 31
  • 37
  • This achieves what the OP was asking for, however do note that this style makes all text black (on my system, highlighted text is usually white, because black on dark blue is too unreadable). – Roman Starkov Mar 12 '12 at 17:59
  • @romkyns just create a regular trigger that sets the foreground to "HighlightTextBrushKey" when IsSelected is true. I'll submit an edit to the answer, but it fixes the issue you mention. This is the right way to do what the OP wants (the dictionary approaches cause unwanted visual side effects for some users depending on their themes)... – BrainSlugs83 Aug 28 '14 at 04:44
  • Quite useful... I like this method better because the colors aren't overriding any other color, and it works while the control is disabled, which was my use case. Thanks! – Mark W Jun 03 '15 at 20:26
  • This works for WPF on .Net 4.6. You cannot create a style for `ListBoxItem` that directly overrides the `Background` via IsSelected trigger (this works for many properties, but not for the background). I guess this is a problem with the execution order of different triggers. You really have to override the control template. – Patrick Stalph Jul 11 '17 at 09:03
13

You have to override some properties of SystemColors. Take a look at SystemColors Class (MSDN). There are more properties than InactiveSelectionHighlightBrushKey, e.g. InactiveSelectionHighlightTextBrushKey which affects the color of text.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red"/>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="White"/>
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Yellow"/>
        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}" Color="Blue"/>
        <Style TargetType="ListViewItem">
            <Setter Property="FontSize" Value="20" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Padding" Value="25,5" />
        </Style>
    </Window.Resources>
    <StackPanel Orientation="Horizontal">
        <ListView>
            <ListViewItem Content="Item" />
            <ListViewItem Content="Item" />
        </ListView>
        <ListView>
            <ListViewItem Content="Item" />
            <ListViewItem Content="Item" />
        </ListView>
    </StackPanel>
</Window>

enter image description here

pr0gg3r
  • 4,254
  • 1
  • 36
  • 27
2

In older .NET Frameworks overriding system colors does't work. Solution that works in .NET Framework 4.0 is here.

<ListView>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border x:Name="Bd"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Background="{TemplateBinding Background}"
                        Padding="{TemplateBinding Padding}"
                        SnapsToDevicePixels="true">
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                </Border>
                <ControlTemplate.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive"
                                        Value="False" />
                            <Condition Property="IsSelected"
                                        Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Background"
                                TargetName="Bd"
                                Value="DarkOrange" />
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive"
                                        Value="True" />
                            <Condition Property="IsSelected"
                                        Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Background"
                                TargetName="Bd"
                                Value="OrangeRed" />
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Works both for ListBox and ListView.

Gabriel
  • 377
  • 1
  • 3
  • 15
  • While this might be a valuable hint to solve the problem, a good answer also demonstrates the solution. Please [EDIT](http://stackoverflow.com/posts/5419867/edit) to provide example code to show what you mean. Alternatively, consider writing this as a comment instead – ρяσѕρєя K Jan 16 '17 at 09:21
2

Based on this other answer I used the following to make the active & inactive colors the same without hardcoding the actual value:

<ListBox.Resources>
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" 
                     Color="{x:Static SystemColors.HighlightColor}"/>
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}"
                     Color="{x:Static SystemColors.HighlightTextColor}"/>
</ListBox.Resources>

Having the same colors for both active & inactive may not be ideal, but the default colors were so faint it was hard to tell which item was selected when it was inactive; this is a definite improvement.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
1

Overriding the SystemColors, as most of the other answers advise, did not work for me. I ended up just editing the default style for ListBoxItem and setting ItemContainerStyle on the specific ListBox to the edited style. It's relatively painless compared to editing default styles for other controls. All you have to do is change the Item.SelectedInactive.Background and the Item.SelectedInactive.Border to the colors you want.

   <SolidColorBrush x:Key="Item.Static.Background" Color="#FFFCFCFC" />
    <SolidColorBrush x:Key="Item.Static.Border" Color="#FFFCFCFC" />
    <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="ModifiedColorListBox" 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" 
                        BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                        Background="{TemplateBinding Background}" 
                        Padding="{TemplateBinding Padding}" 
                        SnapsToDevicePixels="true">
                        <ContentPresenter 
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </Border>
                    <ControlTemplate.Triggers>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.MouseOver.Background}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.MouseOver.Border}" />
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="False" />
                                <Condition Property="IsSelected" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedInactive.Background}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedInactive.Border}" />
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True" />
                                <Condition Property="IsSelected" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="Bd" Property="Background" Value="{StaticResource Item.SelectedActive.Background}" />
                            <Setter TargetName="Bd" Property="BorderBrush" Value="{StaticResource Item.SelectedActive.Border}" />
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter TargetName="Bd" Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

And then usage from xaml:

<ListBox
    Name="SomeListBox"
    ItemContainerStyle="{StaticResource ModifiedColorListBox}"
    ItemsSource="{Binding SomeCollection}"
    SelectedItem="{Binding SomeObject}">
</ListBox>
sixth_way
  • 41
  • 2
  • 7
0

For me this did the trick:

 <ListBox HorizontalContentAlignment="Stretch">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Label  Margin="-5, -2,-5,-2" Content="{Binding Item}">
                            <Label.Style>
                                <Style TargetType="Label">
                                    <Style.Triggers>
                                        <MultiDataTrigger>
                                            <MultiDataTrigger.Conditions>
                                                <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBox}},Path=IsFocused}" Value="False"/>
                                                <Condition Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True"/>
                                            </MultiDataTrigger.Conditions>
                                            <Setter Property="Background" Value="CornflowerBlue"/>
                                        </MultiDataTrigger>
                                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
                                            <Setter Property="Foreground" Value="White"/>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="False">
                                            <Setter Property="Foreground" Value="Black"/>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Label.Style>
                        </Label>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
Martin Ch
  • 1,337
  • 4
  • 21
  • 42