`ComboBoxItem` 的动画高亮效果

Hightlight effect with animation for `ComboBoxItem`s

我想在 ComboBox 元素的 ComboBoxItem 背景上做一个简单的动画效果。当指针位于项目上方时,项目应以定义的颜色突出显示,并在指针离开时恢复为原始状态。

这是我的模板

<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <Border x:Name="Border"
                        Padding="2"
                        SnapsToDevicePixels="true">
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Style.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Trigger.EnterActions>
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ColorAnimation Duration="0:0:0.01"
                                                                Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
                                                                To="#FFA7ACD4" />
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </Trigger.EnterActions>
                                    <Trigger.ExitActions>
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ColorAnimation Duration="0:0:0.6"
                                                                Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)"
                                                                To="White" />
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </Trigger.ExitActions>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                              Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ColorItemSelectedBackground}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0"
                                            Value="{StaticResource SelectedUnfocusedColor}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我有一种预感,触发器是必经之路。 我试过将 VisualSateGroupsMouseEnterMouseOver 一起使用。 MouseEnter 什么也没做,MouseOver 也没有恢复到原来的状态。 我认为这个例子最能反映我想要实现的目标。

WPF 对我来说并不陌生,但我发现依赖对象非常混乱。特别是有多种方法可用于操纵或动画属性。 打开保管箱后出现NullReferenceException。这对我来说很清楚。根本没有链接到故事板的依赖对象,但在这种方法中,我无法在 Style 触发器中设置 TargetName 属性。

正确的方法是什么?如果使用 VisualSate 是 "native" 方法,那么我更喜欢这个而不是触发器。

更新

这有效,但它使用了触发器。我更喜欢仅出于学习目的使用 VisualStateGroups 的解决方案。

<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <ControlTemplate.Triggers>
                    <Trigger Property="IsHighlighted" Value="true">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.01"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="#FFA7ACD4" />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>

                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.6"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="White" />
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>
                </ControlTemplate.Triggers>
                <Border x:Name="Border"
                        Padding="2"
                        SnapsToDevicePixels="true"
                        Background="White">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                              Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="{DynamicResource ColorItemSelectedBackground}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0"
                                            Value="{StaticResource SelectedUnfocusedColor}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

试试这个:

<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">
                <Border x:Name="Border"
                                    Padding="2"
                                    SnapsToDevicePixels="true"
                                    Background="White">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="Common">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <ColorAnimation
                                                        Storyboard.TargetName="Border"
                                                        Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                        To="White" />
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:1"
                                                        Storyboard.TargetName="Border"
                                                        Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                        To="#FFA7ACD4" />
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border" 
                                                                                  Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="Red" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                                  Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="Green" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <ContentPresenter />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

作为 mm8 回答的旁注。这是突出显示所选项目和突出显示鼠标指针下的项目的唯一方法。

VisualStateManager 似乎无法 return 到 Selected 状态,因为它被 Normal 状态覆盖。

因此,我删除了 VisualStateManager 以支持 multi-trigger 方法。

<Color x:Key="ItemBackground">White</Color>
<Color x:Key="ItemSelectedBackground">#FFC5CBF9</Color>
<Color x:Key="ItemMouseOverBackground">#FFA7ACD4</Color>

<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="OverridesDefaultStyle" Value="true" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ComboBoxItem}">

                <ControlTemplate.Triggers>
                    <!-- Trigger for hightlighting items on MouseOver -->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsHighlighted" Value="true" />
                            <Condition Property="IsSelected" Value="false" />
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.01"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="{StaticResource ItemMouseOverBackground}" />
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.EnterActions>

                        <MultiTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.2"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="{StaticResource ItemBackground}" />
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.ExitActions>
                    </MultiTrigger>
                    <!-- Trigger for hightlighting selected items on MouseOver -->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsHighlighted" Value="true" />
                            <Condition Property="IsSelected" Value="true" />
                        </MultiTrigger.Conditions>
                        <MultiTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.01"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="{StaticResource ItemMouseOverBackground}" />
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.EnterActions>

                        <MultiTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimation Duration="0:0:0.2"
                                                    Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="{StaticResource ItemSelectedBackground}" />
                                </Storyboard>
                            </BeginStoryboard>
                        </MultiTrigger.ExitActions>
                    </MultiTrigger>
                </ControlTemplate.Triggers>

                <Border 
                    x:Name="Border"
                    Padding="2"
                    SnapsToDevicePixels="true"
                    Background="White">
                    <!--<VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames
                                        Storyboard.TargetName="Border"
                                        Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="{StaticResource ItemBackground}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames
                                        Storyboard.TargetName="Border"
                                        Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="{StaticResource ItemMouseOverBackground}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected" />
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames
                                        Storyboard.TargetName="Border"
                                        Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0" Value="{StaticResource ItemSelectedBackground}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="SelectedUnfocused">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
                                        <EasingColorKeyFrame KeyTime="0"
                                            Value="{StaticResource SelectedUnfocusedColor}" />
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>-->
                    <ContentPresenter />
                </Border>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>