Reputation: 3241
This question has been asked & answered on here about a dozen times, but none of the given answers seem to work. The question: In a WPF ListBox, how do you change the highlight color (of the selected item, and/or the 'mouseover' item)?
This does not work (per here) - the highlight remains as default:
<StackPanel>
<StackPanel.Resources>
<Style x:Key="ListBoxSelectedItemsStyle" TargetType="{x:Type ListBoxItem}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Black" />
</Style.Resources>
</Style>
</StackPanel.Resources>
<ListBox ItemContainerStyle="{StaticResource ListBoxSelectedItemsStyle}">
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
<ListBoxItem>Item3</ListBoxItem>
</ListBox>
</StackPanel>
This also does not work (slight variation, per here):
<StackPanel>
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Yellow"/>
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
<ListBoxItem>Item3</ListBoxItem>
</ListBox>
</StackPanel>
This also does not work (per here):
<StackPanel>
<ListBox>
<ListBox.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Black"/>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Black"/>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
<ListBoxItem>Item3</ListBoxItem>
</ListBox>
</StackPanel>
Many many answers include some variation of this (i.e. here, etc) - but no matter which I use, nothing changes. The highlight remains unaffected.
Upvotes: 3
Views: 1132
Reputation: 70701
All three of the versions you tried amount to basically the same thing: they provide a new resource, using the same key that is used by the default ListBoxItem
control template. In theory, by providing a new resource item with the same key, when it comes time for the framework to look for the appropriate resource, it will traverse the loaded resource dictionaries, find yours first, and use that instead of the original one used by default.
But it seems that there are a couple of problems:
ListBoxItem
style, it uses regular strings as keys, not these properties in the SystemColors
class. The current key name is "Item.SelectedActive.Background"
for setting the background when the item is selected and has focus.There is probably some way to still get it to work. But figuring that out would take time, stepping through the code in the debugger and watching to see what WPF is doing when the control is initialized and when the trigger is triggered. Such an investigation would probably shed light on how WPF is looking up the resource, and how one might manage to cause your own resource with the same key to be found instead.
But at the moment, I don't have time to do all that. And I do know how to make it work via brute force. One of the biggest hammers in the XAML toolbox is the "Edit Template" command in the XAML Designer. For this particular purpose, you want to create a copy of the ListBoxItem
template so you can use an edited version of that. Right-click on the ListBox
in Design mode in the XAML editor and go to this menu:
Choose the "Edit a Copy…" menu item.
That will add new resources to your file that look like this:
<SolidColorBrush x:Key="Item.MouseOver.Background" Color="#1F26A0DA"/>
<SolidColorBrush x:Key="Item.MouseOver.Border" Color="#a826A0Da"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3DDADADA"/>
<SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FFDADADA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
<SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
<Style x:Key="ListBoxItemStyle1" 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}" 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>
It will also update the ListBox
in the XAML to reference that style for the item container template. At this point, you can edit the resources to your heart's content. For example, change the brush for the "Item.SelectedActive.Background"
key:
<SolidColorBrush x:Key="Item.SelectedActive.Background" Color="Black"/>
Given that the WPF documentation does discuss the resource hierarchy and how resources are found by key, it does seem like it should be possible to get this to work without completely overriding the item container style like this. But I don't see a way how at the moment.
For what it's worth, the above is basically what is being proposed in Changing WPF Listbox SelectedItem text color and highlight/background Color using C#, minus all the extra details found in that question. In a sense, this question could be considered a duplicate of that.
There are a couple of other questions that you might find relevant, if this is something you run into a lot and want a less messy solution. In particular, you can use markup extensions to customize how styles are handled, allowing you to merge or otherwise manipulate the resource dictionaries as they are handled at compile time. This is a lot more complicated approach, but might be worth it if this comes up a lot in your projects. See e.g.: XAML Combine Styles How to apply multiple styles in WPF Your question really is not a duplicate of either of those, but the basic technique could be applied in your situation anyway.
Upvotes: 1