pseudoDust
pseudoDust

Reputation: 1386

Keeping custom style of ListBoxItem when selected

I have a ListBox where the background color of the items are bound to some property of the entry:

<ListBox ItemsSource="{Binding ObservableCollectionOfFoos}" >
    <ListBox.ItemContainerStyle >
        <Style TargetType="ListBoxItem" >
            <Setter Property="Content" Value="{Binding SomePropertyOfFoo}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding AnotherPropertyOfFoo}" Value="true">
                    <Setter Property="Background" Value="Green" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

This works, but when I mouse over or select an item the background changes (unsurprisingly perhaps) to the default mouse over / selected color.

I'm new to WPF and I'm not sure I'm going about doing this kind of thing correctly, I thought maybe I need to use ItemContainerStyleSelector, but I'm confused as to how to use it, and it seems silly to have to create a class just for this small thing...

What I also thought was to create an IValueConverter from boolean to the color, and then bind though it without having to use DataTrigger as a different approach, would that be more elegant? would that some how help me with this problem?

Edit

It would also be nice if I could change the background color of the selected item to a different color based on AnotherPropertyOfFoo, if it's not too much to ask

edit 2 (extension to comment on @Sheridan answer):

this does not work

    <ListBox>
        <ListBox.Items>
            <ListBoxItem>one</ListBoxItem>
            <ListBoxItem>two</ListBoxItem>
            <ListBoxItem>three</ListBoxItem>
            <ListBoxItem>four</ListBoxItem>
        </ListBox.Items>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Background" Value="Green" />
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Red" />
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Red" />
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
                </Style.Resources>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

Upvotes: 0

Views: 295

Answers (2)

vitaliy zadorozhnyy
vitaliy zadorozhnyy

Reputation: 1246

You can also override Template of ListBoxItem, extract default using blend and override or use some already mentioned here.

Edit

Actually it is not so hard to override Template :) and I guess it is most correct way to solve your problem. Try this ItemContainer style. It replaces default ListBoxItem style->Template. To see how does it work - in triggers you can change any property of listbox item.

 <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="Padding" Value="2,0,0,0"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <Border Name="Border" Padding="2" SnapsToDevicePixels="true">
                                <ContentPresenter />
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="true">
                                    <Setter TargetName="Border" Property="Background" Value="LightBlue"/>
                                </Trigger>
                                <Trigger Property="IsSelected" Value="true">
                                    <Setter TargetName="Border" Property="Background" Value="Blue"/>
                                </Trigger>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Foreground" Value="Gray"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>

The default style of ListBoxItem you can find here to make required modifications.

Upvotes: 1

Sheridan
Sheridan

Reputation: 69985

Try using this:

<ListBox ItemsSource="{Binding ObservableCollectionOfFoos}" >
    <ListBox.ItemContainerStyle >
        <Style TargetType="ListBoxItem" >
            <Setter Property="Content" Value="{Binding SomePropertyOfFoo}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding AnotherPropertyOfFoo}" Value="true">
                    <Setter Property="Background" Value="Green" />
                </DataTrigger>
            </Style.Triggers>
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
            </Style.Resources>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

The SystemColors.HighlightBrushKey represents the default background colour of the selected item in collection controls... here it is set to Transparent, but you can set it to which ever colour you prefer.

UPDATE >>>

This code works just fine... if you change the first SolidColorBrush in the Resources section to Red, then the selected item background colour will be Red. Your Binding of AnotherPropertyOfFoo will not affect the selected item as there is no relationship between the two. To achieve that, you can try this instead:

<ListBox ItemsSource="{Binding ObservableCollectionOfFoos}" >
    <ListBox.ItemContainerStyle >
        <Style TargetType="ListBoxItem" >
            <Setter Property="Content" Value="{Binding SomePropertyOfFoo}"/>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{Binding AnotherPropertyOfFoo}" />
                </DataTrigger>
            </Style.Triggers>
            <Style.Resources>
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="Black" />
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="Black" />
            </Style.Resources>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Now the selected item will get the background colour from the AnotherPropertyOfFoo property.

Upvotes: 0

Related Questions