11

According to this, overriding the ControlBrushKey resource should change the background color of a ListBox selected item when it doesn't have focus. I created a simple example to disprove this:

 <StackPanel>
    <ListBox>
      <ListBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightBlue"/>
        <!--SelectedItem without focus but doesn't really work-->
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Orange" />
      </ListBox.Resources>
      <ListBoxItem>
        Item 1
      </ListBoxItem>
      <ListBoxItem>
        Item 2
      </ListBoxItem>
    </ListBox>
    <TextBox></TextBox>
  </StackPanel>

If you run this in .NET 4.5 you can see that it only changes the in-focus color, but not the not-in-focus (it works in .NET 4.0). Any idea why?

Edit: This seems to be duplicate of List/Combo Box Background And Selected Colours Under .net 4.5.

Community
  • 1
  • 1
Doron Yaacoby
  • 9,412
  • 8
  • 48
  • 59
  • possible duplicate of [List/Combo Box Background And Selected Colours Under .net 4.5](http://stackoverflow.com/questions/12007918/list-combo-box-background-and-selected-colours-under-net-4-5) – Doron Yaacoby Oct 03 '12 at 16:00

4 Answers4

16

Try the following for changing the selected ListBoxItem's background color when it has lost focus:

XAML

<ListBox.Resources>    
    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightBlue"/> 
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey }" Color="Orange" />    
</ListBox.Resources>

C#

listBox.Resources.Add(SystemColors.InactiveSelectionHighlightBrushKey, 
                      new SolidColorBrush(Colors.Orange));

I hope it works for you.

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
1

It's all about the default templates of the controls, if they do not use the system colors as they did in .NET 4 this will simply not change anything.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Isn't that a breaking change? And anyway it looks like ControlBrushKey is still being used. – Doron Yaacoby Oct 03 '12 at 14:32
  • @DoronYaacoby: It's not a breaking change because relying on anything within a control template is foolish. It's a bit like invoking private methods via reflection. – H.B. Oct 03 '12 at 14:42
  • As this is the accepted and most up-voted answer to that question, I'm guessing a great many people found this solution to be the simplest one so it will break a lot of applications. But anyway, what is the correct way to achieve what I want? – Doron Yaacoby Oct 03 '12 at 14:50
  • @DoronYaacoby: Define your own template. – H.B. Oct 03 '12 at 14:55
  • Isn't that an overkill? I just want to change.a couple of colors, I'm reluctant to copy&paste and then mainatain a huge block of xaml. – Doron Yaacoby Oct 03 '12 at 15:19
  • @DoronYaacoby: Well, the architecture isn't that great in this regard, if there was a `ColorScheme` property that could be adjusted that would be great but as this is not the case overwriting the whole template is the only really clean option. – H.B. Oct 03 '12 at 16:15
0

Here's what I came up with that doesn't involve changing system colors or control templates. Simply wrap the ListBox in a new UserControl.

public partial class StyledListBox : UserControl
{
    public DataTemplate ItemTemplate
    {
        get { return (DataTemplate)GetValue(ItemTemplateProperty); }
        set { SetValue(ItemTemplateProperty, value); }
    }

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }

    public StyledListBox()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(StyledListBox), new FrameworkPropertyMetadata(null));
    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(StyledListBox), new FrameworkPropertyMetadata(null));

    public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(StyledListBox), new FrameworkPropertyMetadata(null)
    {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
    });
}

XAML:

<UserControl x:Class="StyledListBox"

     <ListBox ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:StyledListBox}}}"
              SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:StyledListBox}}}">

        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border>
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"
                                             Value="True">
                                    <Setter Property="Background" Value="Red" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>

                    <ContentPresenter ContentTemplate="{Binding ItemTemplate, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StyledListBox}}}" />
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</UserControl>

Then simply use the wrapper UserControl as if it were a ListBox. Any other ListBox properties you want to control can simply be added to the wrapper in the same manner as ItemsSource and SelectedItem from my example.

bugged87
  • 3,026
  • 2
  • 26
  • 42
-2

The solution to this is adding

FrameworkCompatibilityPreferences.AreInactiveSelectionHighlightBrushKeysSupported = false;

before calling

InitializeComponent();
Daniel
  • 1,064
  • 2
  • 13
  • 30
  • Throws exception: "The property 'AreInactiveSelectionHighlightBrushKeysSupported' cannot be changed. The 'FrameworkCompatibilityPreferences' class has been sealed." – bugged87 Jan 29 '15 at 23:29
  • @bugged87 add this inside of try/catch block. My programs use this and everything looks as intended on all versions of Windows – Daniel Jan 30 '15 at 04:25
  • 1
    Sure, adding a try/catch handles the exception, but this code doesn't seem to make the OP's code work. I'm using .NET 4.5 on Windows 8.1. – bugged87 Jan 30 '15 at 14:14