Change background color for selected ListBox item
Asked Answered
H

7

67

This is my XAML so far.

<ScrollViewer Grid.Column="1" Grid.RowSpan="2">

    <ListBox   Background="Black" ItemsSource="{Binding Path=ActiveLog}" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Background="Black">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>
                    <TextBlock Grid.Column="0" Grid.Row="0" Foreground="White">
                        <TextBlock >Date:</TextBlock>
                        <TextBlock  Text="{Binding Path=LogDate}"/>
                    </TextBlock>
                    <TextBlock Grid.Column="1" Grid.Row="0" Foreground="White">
                        <TextBlock >Severity:</TextBlock>
                        <TextBlock  Text="{Binding Path=Severity}"/>
                    </TextBlock>
                    <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="1" Foreground="LightGray" Text="{Binding Path=Message}"></TextBlock>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
        <ListBox.Template>
            <ControlTemplate>
                <StackPanel Background="Black" IsItemsHost="True" >
                </StackPanel>
            </ControlTemplate>
        </ListBox.Template>

    </ListBox>
</ScrollViewer>

The only problem is that the selected item has a blue box to the right. I assume there is a way to change the selection color, but I can't find it.

Hl answered 26/1, 2010 at 8:26 Comment(0)
T
46

You need to use ListBox.ItemContainerStyle.

ListBox.ItemTemplate specifies how the content of an item should be displayed. But WPF still wraps each item in a ListBoxItem control, which by default gets its Background set to the system highlight colour if it is selected. You can't stop WPF creating the ListBoxItem controls, but you can style them -- in your case, to set the Background to always be Transparent or Black or whatever -- and to do so, you use ItemContainerStyle.

juFo's answer shows one possible implementation, by "hijacking" the system background brush resource within the context of the item style; another, perhaps more idiomatic technique is to use a Setter for the Background property.

Templia answered 26/1, 2010 at 8:40 Comment(4)
Ok, now it makes a lot more sense. Thanks.Hl
It doesn't work if you just use a 'Setter' for the 'Background' property in 'IsSelected' is true in ItemContainerStyle. It still uses the system highlight color. :(Bagnio
To change the Background color of selected ListBoxItem, you need to retemplate the ListBoxItem. ref: the comment in the accepted answer in here . VS 2012, .Net Framework 4.5.Bagnio
Can you provide a working sample of a solution based on ListBox.ItemContainerStyle? It seems like it doesn't work, the only working solution (not based on system colors) is retemplating.Physoclistous
P
79
<UserControl.Resources>
    <Style x:Key="myLBStyle" TargetType="{x:Type ListBoxItem}">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                             Color="Transparent"/>
        </Style.Resources>
    </Style>
</UserControl.Resources> 

and

<ListBox ItemsSource="{Binding Path=FirstNames}"
         ItemContainerStyle="{StaticResource myLBStyle}">  

You just override the style of the listboxitem (see the: TargetType is ListBoxItem)

Prefer answered 26/1, 2010 at 8:36 Comment(3)
This no longer applies for Windows-8 which uses static colors in the ControlTemplate triggers. You'd have to derive the base Style and specify the over-ridden brushes in those triggers or give the colors directly. https://mcmap.net/q/296797/-setting-background-color-or-wpf-4-0-listbox-windows-8Payday
@Payday does this also apply to wpf in .net 4.5?Micronutrient
@Micronutrient Yes with .net4.5 on Windows-7 the ControlTemplate uses SystemColors for states. However in Windows-8 it no longer does as explained Here. Difference seems more on per OS version than per .net versionPayday
C
58

Or you can apply HighlightBrushKey directly to the ListBox. Setter Property="Background" Value="Transparent" did NOT work. But I did have to set the Foreground to Black.

<ListBox  ... >
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True" >
                    <Setter Property="FontWeight" Value="Bold" />
                    <Setter Property="Background" Value="Transparent" />
                    <Setter Property="Foreground" Value="Black" />
                </Trigger>
            </Style.Triggers>
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
            </Style.Resources>
        </Style>                
    </ListBox.ItemContainerStyle>
</ListBox>
Collator answered 26/7, 2011 at 19:17 Comment(1)
this solution works for me, but @juFo's answer dosen't, because all the control gives transparnt, dons't see any text.Terranceterrane
T
46

You need to use ListBox.ItemContainerStyle.

ListBox.ItemTemplate specifies how the content of an item should be displayed. But WPF still wraps each item in a ListBoxItem control, which by default gets its Background set to the system highlight colour if it is selected. You can't stop WPF creating the ListBoxItem controls, but you can style them -- in your case, to set the Background to always be Transparent or Black or whatever -- and to do so, you use ItemContainerStyle.

juFo's answer shows one possible implementation, by "hijacking" the system background brush resource within the context of the item style; another, perhaps more idiomatic technique is to use a Setter for the Background property.

Templia answered 26/1, 2010 at 8:40 Comment(4)
Ok, now it makes a lot more sense. Thanks.Hl
It doesn't work if you just use a 'Setter' for the 'Background' property in 'IsSelected' is true in ItemContainerStyle. It still uses the system highlight color. :(Bagnio
To change the Background color of selected ListBoxItem, you need to retemplate the ListBoxItem. ref: the comment in the accepted answer in here . VS 2012, .Net Framework 4.5.Bagnio
Can you provide a working sample of a solution based on ListBox.ItemContainerStyle? It seems like it doesn't work, the only working solution (not based on system colors) is retemplating.Physoclistous
B
30

I had to set both HighlightBrushKey and ControlBrushKey to get it to be correctly styled. Otherwise, whilst it has focus this will correctly use the transparent HighlightBrusKey. Bt, if the control loses focus (whilst it is still highlighted) then it uses the ControlBrushKey.

<Style.Resources>
    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>

When Using .Net 4.5 and above, use InactiveSelectionHighlightBrushKey instead of ControlBrushKey:

<Style.Resources>
    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
</Style.Resources>

Hope this helps someone out.

Befoul answered 24/11, 2011 at 16:24 Comment(3)
This helped me a lot. I didn't know what was the SystemColors brush used when the ListBox was not focused :) +1Involucre
This was critical to me for making the background transparent when selecting on right click. Thanks!Accountancy
Use InactiveSelectionHighlightBrushKey instead of ControlBrushKey from .NET 4.5.Biogenesis
B
20

I've tried various solutions and none worked for me, after some more research I've found a solution that worked for me here

https://gist.github.com/LGM-AdrianHum/c8cb125bc493c1ccac99b4098c7eeb60

   <Style x:Key="_ListBoxItemStyle" 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="Yellow"/>
                                <Setter Property="Foreground" Value="Red"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

 <ListBox ItemContainerStyle="{DynamicResource _ListBoxItemStyle}"
                 Width="200" Height="250"
                 ScrollViewer.VerticalScrollBarVisibility="Auto"
                 ScrollViewer.HorizontalScrollBarVisibility="Auto">
            <ListBoxItem>Hello</ListBoxItem>
            <ListBoxItem>Hi</ListBoxItem>
        </ListBox>

I posted it here, as this is the first google result for this problem so some others may find it useful.

Bona answered 3/7, 2020 at 11:45 Comment(4)
This works. The Setter of above Style can also be placed directly inside of <ListBox><ListBox.ItemContainerStyle> ... </ListBox.ItemContainerStyle></ListBox> as an alternative.Unearth
The only solution works for my complicated ListItem DataTemplate. All above proposed solutions (included marked as accepted) just not work. Thank you, CuicaS!Soileau
Perfect. Worked with no issues.Worship
I know this is old but I've literally spent hours trying to get this to work with data template and this as the first solution that worked. THANK YOU!!!Magenmagena
C
12

You have to create a new template for item selection like this.

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="ListBoxItem">
            <Border
                BorderThickness="{TemplateBinding Border.BorderThickness}"
                Padding="{TemplateBinding Control.Padding}"
                BorderBrush="{TemplateBinding Border.BorderBrush}"
                Background="{TemplateBinding Panel.Background}"
                SnapsToDevicePixels="True">
                <ContentPresenter
                    Content="{TemplateBinding ContentControl.Content}"
                    ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                    HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                    VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
                    SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>
Click answered 30/5, 2015 at 0:10 Comment(1)
A good answer is more than a working answer, the OP should understand his mistake rather than just copy pasting it. Otherwise he/she'll be back a week later asking the same question in a different context...Ombudsman
X
9

If selection is not important, it is better to use an ItemsControl wrapped in a ScrollViewer. This combination is more light-weight than the Listbox (which actually is derived from ItemsControl already) and using it would eliminate the need to use a cheap hack to override behavior that is already absent from the ItemsControl.

In cases where the selection behavior IS actually important, then this obviously will not work. However, if you want to change the color of the Selected Item Background in such a way that it is not visible to the user, then that would only serve to confuse them. In cases where your intention is to change some other characteristic to indicate that the item is selected, then some of the other answers to this question may still be more relevant.

Here is a skeleton of how the markup should look:

    <ScrollViewer>
        <ItemsControl>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    ...
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
Xi answered 13/12, 2014 at 21:36 Comment(1)
This is a clear case in which less is more... thank you for this suggestion, I was struggle in useless cheap hacks and I didn't realize that the solution was so simple... Thank you againPassible

© 2022 - 2024 — McMap. All rights reserved.