Changing text foreground color on mouseover and selection with Silverlight 4 ListBox

I’m trying to accomplish the following scenario with a Silverlight ListBox:

  1. Normal items have a foreground text color of black and background color of white
  2. Selected items have a foreground text color of white and a background color of dark blue
  3. On mouse-over the background becomes a orangish and the foreground text color is black

I have each of those pieces working individually but can’t get them all working together. I started by retemplating the ListBoxItem, wrapping the ContentPresenter in a ContentControl and using Visual States to change the foreground and backgrounds for selected and mouseover states. But the selected and mouseover states can both apply simultaneously, which causes problems when you mouseover a selected item and then mouse out. The recommendation is to avoid changing a single property in states that are in different state groups. So I wrapped another ContentControl around the first content control, and tried changing the the parent ContentControl’s foreground in one visual state and the child ContentControl’s foreground in the other visual state. But it looks like ContentControl’s don’t inherit the foreground property from their parent, so that doesn’t seem to work (even if I retemplate the ContentControl to remove the explicit foreground property setter).

So I’m a bit stuck – don’t know what to try next. Here’s the XAML from my most recent iteration

<Style x:Key="SimpleListBoxItem" TargetType="ListBoxItem">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <ColorAnimation Duration="0" To="Yellow" Storyboard.TargetName="ContentControlChild"
                                                                        Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)" />
                                </Storyboard>

                            </VisualState>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Mouse_Over" />
                                    <ColorAnimation Duration="0" To="{StaticResource G360-MainBlack}" Storyboard.TargetName="ContentControlChild"
                                                                        Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Unfocused"/>
                            <VisualState x:Name="Focused">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Selected1" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Selected1" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Selected1" />
                                    <ColorAnimation Duration="0" To="White" Storyboard.TargetName="ContentControlParent"
                                                                        Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="Selected1" />
                                    <ColorAnimation Duration="0" To="White" Storyboard.TargetName="ContentControlParent"
                                                                        Storyboard.TargetProperty="(Control.Foreground).(SolidColorBrush.Color)" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Rectangle x:Name="Selected1" Opacity="0" Fill="{StaticResource G360-ListSelected}" />
                    <Rectangle x:Name="Mouse_Over" RadiusX="2" RadiusY="2" Stroke="{StaticResource ListBorderSelected}" Opacity="0" Margin="2" Fill="{StaticResource -ListMouseOver}" />
                    <ContentControl x:Name="ContentControlParent">

                        <ContentControl x:Name="ContentControlChild">
                            <ContentControl.Style>
                                <Style TargetType="ContentControl">
                                    <Setter Property="HorizontalContentAlignment" Value="Left"/>
                                    <Setter Property="VerticalContentAlignment" Value="Top"/>
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate TargetType="ContentControl">
                                                <ContentPresenter
                                                      Content="{TemplateBinding Content}"
                                                      ContentTemplate="{TemplateBinding ContentTemplate}"
                                                      Cursor="{TemplateBinding Cursor}"
                                                      Margin="{TemplateBinding Padding}"
                                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </ContentControl.Style>
                            <ContentPresenter x:Name="ContextText" Content="{TemplateBinding Content}" VerticalAlignment="Center" Margin="8,5,4,5"/>
                        </ContentControl>
                    </ContentControl>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
Add Comment
2 Answer(s)

ContentPresenters inherit the style attributes (font, foreground, etc…) from the parent, not ContentControl.

I agree with Rob that having two ContentControls is the solution that gives you the most control over the animations. This also allows to do some fade-in/fade-out transitions between the states, something that is difficult to achieve with just one element.

[edit] You don’t want to template the ListBoxItem. Instead, work with the ItemContainerStyle. This is the best way to achieve what you want with the least headaches.

Cheers,
Laurent

Answered on July 11, 2016.
Add Comment

I would create two ContentControls in the template, one of which has its colour modified by the “selected” stategroup, and another which is always orange but has its opacity modified by the mouseover stategroup.

Sounds like a waste but it gives you the most control over animations if you decide to bring them in…

Answered on July 11, 2016.
Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.