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

标签 wpf blend visualstatemanager

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

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

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

enter image description here

这是按钮的模板:

<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 状态),显然如果需要从一种颜色淡入另一种颜色可以更改 Storyboard动画来实现它。

<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 转换。如果只将它添加到过渡中,一旦进入状态,颜色就会恢复。

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

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)

关于wpf - 在鼠标悬停和按下状态之间跳过 VSM 中的正常按钮状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33691926/

相关文章:

c# - 显示动画直到操作完成 wpf

c# - 从 WPF 中的数据绑定(bind)数据网格中排除列

c# - XAML 样式/基类中 VisualStateGroup/VisualState 的继承

.net - 你能强制鼠标移动吗?

wpf - UI 选项卡控制调试和部署版本之间的可见性变化

c# - 是否可以使用 C#7 绑定(bind)到 WPF 中的 ValueTuple 字段

tfs - Blend for visual studio 2012 连接到 team Foundation Server 2012 服务器每次混合获得焦点

graphics - 如何在手动 "Overlay"混合操作中处理 alpha?

wpf - VisualStateManager 中 MouseOver 和 PointerOver 的区别

xaml - 转到 Listivew 项目 DateTemplate Windows Phone 8.1 中的 VisualState