在鼠标悬停和按下状态之间跳过 VSM 中的正常按钮状态

Skip normal button state in VSM between mouseover and pressed state

按下按钮时的状态转换如下:

Normal -> MouseOver -> Normal -> Pressed -> Normal -> MouseOver

我遇到的问题是 MouseOverPressed 状态在视觉上有很多共同点,并且在这些状态之间向正常的过渡会弄乱动画。作为一个更实际的例子,我有一个按钮,默认情况下它有一个黑色边框,它在 MouseOverPressed 状态下有一个绿色边框。当我按下它时,它首先从绿色变为黑色,然后变为绿色,这是不可取的。在这种情况下,有什么办法可以跳过 Normal 状态或让它看起来很糟糕吗?

这是按钮的模板:

<Button Command="{Binding PlayScene}" Width="220">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Border x:Name="border"
                    BorderThickness="3"
                    Margin="2 0"
                    BorderBrush="{DynamicResource ButtonBorderBrush}"
                    RenderTransformOrigin="0.5,0.5">
                <Border.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Border.RenderTransform>
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualStateGroup.Transitions>
                            <VisualTransition GeneratedDuration="0:0:0.2"/>
                            <VisualTransition GeneratedDuration="0:0:0.2" To="Pressed">
                                <VisualTransition.GeneratedEasingFunction>
                                    <BackEase EasingMode="EaseOut"/>
                                </VisualTransition.GeneratedEasingFunction>
                            </VisualTransition>
                            <VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>
                        </VisualStateGroup.Transitions>
                        <VisualState x:Name="Normal"/>
                        <VisualState x:Name="MouseOver">
                            <Storyboard>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightBrush}"/>
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Pressed">
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(Brush.RelativeTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="border">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="1.1"/>
                                </DoubleAnimationUsingKeyFrames>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(Brush.RelativeTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="border">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="1.1"/>
                                </DoubleAnimationUsingKeyFrames>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="border">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="0.95"/>
                                </DoubleAnimationUsingKeyFrames>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="border">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="0.95"/>
                                </DoubleAnimationUsingKeyFrames>
                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
                                    <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightDarkBrush}"/>
                                </ObjectAnimationUsingKeyFrames>
                            </Storyboard>
                        </VisualState>
                        <VisualState x:Name="Disabled"/>
                    </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>

                <Border.Background>
                    <ImageBrush ImageSource="{Binding Image}" Stretch="UniformToFill">
                        <ImageBrush.RelativeTransform>
                            <TransformGroup>
                                <ScaleTransform CenterY="0.5" CenterX="0.5"/>
                                <SkewTransform CenterY="0.5" CenterX="0.5"/>
                                <RotateTransform CenterY="0.5" CenterX="0.5"/>
                                <TranslateTransform/>
                            </TransformGroup>
                        </ImageBrush.RelativeTransform>
                    </ImageBrush>
                </Border.Background>

                <ContentPresenter x:Name="contentPresenter" />
            </Border>
        </ControlTemplate>
    </Button.Template>
</Button>

视觉状态转换 运行 在进入实际状态之前。由于您没有在过渡中设置画笔,它们默认返回到基本值(在本例中为 ButtonBorderBrush)。我不完全确定你想要的结果,但我的例子假设你想立即将颜色从 HighlightBrush(在 MouseOver 状态)更改为 HighlightDarkBrush(在 Pressed 状态),显然如果需要从一种颜色淡入另一种颜色可以更改故事板动画动画来实现它。

<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Pressed">
    <VisualTransition.GeneratedEasingFunction>
        <BackEase EasingMode="EaseOut"/>
    </VisualTransition.GeneratedEasingFunction>
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource HighlightDarkBrush}"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0:0:0.1" To="MouseOver"/>

本质上,您需要将 Storyboard 添加到 Pressed 状态和 to=Pressed 转换。如果你只把它加到transition中,颜色会在进入状态后恢复。

另请注意,虽然过渡序列看起来好像是

MouseOver -> Normal-> Pressed

事实并非如此。如果您给 Normal 状态一些值(当前它使用的是基值),您可以自己看到这一点,如下所示:

<VisualState x:Name="Normal">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="border">
            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource TestBrush}"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualState>

如果(例如)TestBrush 是红色画笔,则边框只有在鼠标未悬停时才会显示为红色。在状态之间,它将是黑色的 (ButtonBorderBrush)