In this article, we will look at how to alter the background color that appears when a user selects an item in a WPF ListBox
I've been using DataTemplates to organize the layout of WPF ListBoxes for quite a while now. Not only in my WPF Applications, but also by using WPF/WinForms Interop (See my article on devcity for info on how to do this).
If you have used DataTemplates yourself, you will know that they can make a great job of packaging up the data display and allowing you to easily create UIs that would be extremely difficult in Windows Forms.
I was working on a ListBox creation task this week. Nothing very fancy - each item comprised of an Image and two items of text inside a Gradient Border:

The DataTemplate makes a fair job of tweaking the presentation of the data, but when I ran it and selected an item I still got the standard solid blue selection color:

I thought it would be better if I could replace the standard solid blue with something else, but this wasn't something I could achieve by tweaking the DataTemplate. What is needed is a change to the ItemContainerStyle .
It's important to understand the role of these two styling tools. The DataTemplate allows you to package up the individual items of data for display. In the case of a ListBox, you can think of the DataTemplate as sitting inside the ListBoxItem. The ItemContainerStyle is one level up from this. It is responsible for the overall look of the ListBoxItem. So if it helps you to picture the respective roles, you could think of the DataTemplate being contained in the ItemContainerStyle, although that's not exactly how it works.
The question is, how do you change the ItemContainerStyle to create a different selection color and, once this is done, how do you then get the ListBox to apply it?
The answer to the second question is shorter, so I'll deal with that one first. ItemContainerStyle is a property of the ListBox.
<ListBox ItemContainerStyle="{StaticResource SimpleListBoxItem}">
As you would expect, this property takes a Style as its value. And that leads us to the answer to the first question - you create a Style, but (and here's the important bit) you ensure that the Style also contains the ControlTemplate for the ListBox.
When you stop and think about it, this has to be right. As soon as you find you want to change the fundamental look of the ListBox element, you know you have to work with its Template. How much trouble you then go to in order to rewrite the ControlTemplate is a matter of choice.
I began by looking at the full ListBox template, which is fairly lengthy, but then realized two things:
- I already had my DataTemplate in place to do the fancy stuff, so all I needed to do was find the part of the Template that deals with the change of color when an item is selected and tweak this. Everything else could be left unchanged.
- I didn't need to make any changes to the ListBox template. What I was dealing with here was the ListBoxItem template.
When the requirement is as simple as this, a useful approach is to use the Simple Styles, which are available from many sources. If you haven't come across these yet, they are a cut-down version of the full Styles that are used to create the standard WPF elements. One easy way to access and download them is to enter "Styling with ControlTemplates Sample" in the "Look For" text box of the Index, (not the online Search box) on the Visual Studio Help page. This will reveal the sample page, which includes a link to download all the simple styles.
So I took the simple style version of the ListBoxItem and changed the Setter for the IsSelected Trigger. Here is the finished Style:
<Style x:Key="SimpleListBoxItem" TargetType="ListBoxItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<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="{StaticResource AuthorGradient}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Compared to the full version, that's fairly brief. You will see that I changed the Background color of the Border that contains the ListBoxItem in the Template* from the default to a gradient brush named AuthorGradient that I created and stored in the App.xaml file as an Application scope Resource.
* Don't confuse the Border in the Style's Child ControlTemplate with the Border that is used in the DataTemplate.
Now when an item is selected, the user sees this gradient instead of the plain blue:
So the full markup for the ListBox is as follows:
<ListBox x:Name="TemplatedListBox"
HorizontalAlignment="Left" Margin="10"
ItemTemplate="{StaticResource GreenDataTemplate}"
ItemsSource="{Binding}"
ItemContainerStyle="{StaticResource SimpleListBoxItem}" >
</ListBox>
You can see that the ListBox's ItemTemplate is set to the DataTemplate which controls the layout of the data in each ListBoxItem. The ItemContainerStyle contains the template for the ListBoxItem - the one where I changed the selected item color from plain blue to gradient green.
In order for this particular example to work, you will of course need to have a DataSource available to the ListBox's ItemsSource, to which it can bind. However, you don't need to have a bound ListBox, as you will see at the end of this item.
The DataTemplate I used to create the Border/Image/TextBlocks combination is:
<DataTemplate x:Key="GreenDataTemplate" >
<Border BorderBrush="{StaticResource GreenGradient}" BorderThickness="4"
CornerRadius="4" Margin="4,2">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=ImagePath}" Margin="2,0,4,0"
Width="60" Height="70" Stretch="UniformToFill" />
<StackPanel Margin="1" Width="120">
<TextBlock Padding="2,17,5,2"
FontSize="13"
FontWeight="Bold" Foreground="DarkGreen"
Text="{Binding Path=Name}" Height="56">
</TextBlock>
<TextBlock Foreground="Green"
Margin="12,2,0,2"
Text="{Binding Path=Published}" >
</TextBlock>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
I placed this in the Window.Resources block. Again, this will only work if you have a DataSource which contains the three fields I have used in the Bindings for the Image and TextBlocks - ImagePath, Name and Published.
If all this DataBinding and DataTemplates is confusing or more than you need, and you simply want to change the selected item background color, then the following ListBox will be sufficient:
<ListBox ItemContainerStyle="{StaticResource SimpleListBoxItem}">
<ListBoxItem> <TextBlock Margin="4" Padding="5" FontSize="14">Item 1</TextBlock></ListBoxItem>
<ListBoxItem>
<TextBlock Margin="4" Padding="5" FontSize="14">Item 2</TextBlock>
</ListBoxItem>
</ListBox>
When an item is selected, the ItemContainerStyle will kick in and the user will see the gradient:

And finally, if you don't even want the gradient, but just need a different solid color, then simply make the change in the Style:
<Style x:Key="SimpleListBoxItem" TargetType="ListBoxItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<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="Yellow"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see, in this case, I have changed the highlight color to Yellow by editing the Setter for the Border in the IsSelected trigger. The result will be:

So, whether you want to create multicolor effects, tied in with bound DataSources, or even if you simply want to change the selected item solid color, you now know how to do it.