WPF ListView Inactive Selection Color
Asked Answered
H

8

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>
Hexagon answered 19/12, 2008 at 19:43 Comment(0)
S
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>
Stockjobber answered 19/12, 2008 at 20:43 Comment(10)
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 backFourhanded
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.Stockjobber
That's suprising. What happens if you put other listboxes on a form that you don't want styled that way?Fourhanded
The resource is defined at the ListBox level, so it only affects that ListBox.Stockjobber
What's actually happening is you are overriding the style key for all objects that use it.Fourhanded
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.Stockjobber
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.Hexagon
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.Busra
For .NET 4.5, it looks like they changed the key -- see @Recreate answer below.Monopetalous
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: #1462732Matamoros
R
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"/>
Recreate answered 16/2, 2013 at 16:42 Comment(6)
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?Gabrielgabriela
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.Yearround
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).Sostenuto
in .net 4.5 FrameworkCompatibilityPreferences.AreInactiveSelectionHighlightBrushKeysSupported field controls which color is used for the highlight.Ashmead
SystemColors.ControlBrushKey Worked for me, Thank You.Mauve
WPF on net6, had to use SystemColors.InactiveSelectionHighlightBrushKey and SystemColors.InactiveSelectionHighlightTextBrushKeyTelegram
S
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>
Stockjobber answered 19/12, 2008 at 20:43 Comment(10)
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 backFourhanded
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.Stockjobber
That's suprising. What happens if you put other listboxes on a form that you don't want styled that way?Fourhanded
The resource is defined at the ListBox level, so it only affects that ListBox.Stockjobber
What's actually happening is you are overriding the style key for all objects that use it.Fourhanded
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.Stockjobber
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.Hexagon
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.Busra
For .NET 4.5, it looks like they changed the key -- see @Recreate answer below.Monopetalous
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: #1462732Matamoros
C
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

Cyanocobalamin answered 9/9, 2010 at 8:56 Comment(4)
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).Inhibition
@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)...Matamoros
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!Fsh
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.Valentia
C
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

Comrade answered 30/3, 2015 at 10:28 Comment(0)
R
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.

Reo answered 16/1, 2017 at 9:1 Comment(1)
While this might be a valuable hint to solve the problem, a good answer also demonstrates the solution. Please EDIT to provide example code to show what you mean. Alternatively, consider writing this as a comment insteadChappell
S
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.

Saideman answered 10/4, 2019 at 19:34 Comment(0)
M
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>
Mercado answered 16/4, 2022 at 17:41 Comment(0)
S
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>
Selfimmolating answered 6/8, 2015 at 18:6 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.