WPF按钮Style Trigger动画问题:同一属性第二个动画不生效
问题描述
通过Style Trigger给按钮添加动画后,同一属性的第二个动画无法生效。具体表现为:鼠标悬停时按钮尺寸能变为120x45,但点击鼠标时无任何反应。
原始XAML代码
<Window x:Class="TestWpf.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:TestWpf" mc:Ignorable="d" Title="MainWindow" Height="320" Width="340"> <Window.Resources> <QuadraticEase x:Key="easing" EasingMode="EaseOut"/> </Window.Resources> <Grid> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"> <Label Name="label"/> <Button Content="Hello" Width="100" Height="45"> <Button.Style> <Style TargetType="Button"> <Style.Resources> <Storyboard x:Key="press" x:Name="press"> <DoubleAnimation Storyboard.TargetProperty="Width" To="125" Duration="0:0:0.100" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="50" Duration="0:0:0.100" EasingFunction="{StaticResource easing}"/> </Storyboard> <Storyboard x:Key="hover" x:Name="hover"> <DoubleAnimation Storyboard.TargetProperty="Width" To="120" Duration="0:0:0.200" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="45" Duration="0:0:0.200" EasingFunction="{StaticResource easing}"/> </Storyboard> <Storyboard x:Key="leave" x:Name="leave"> <DoubleAnimation Storyboard.TargetProperty="Width" To="100" Duration="0:0:0.300" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="45" Duration="0:0:0.300" EasingFunction="{StaticResource easing}"/> </Storyboard> </Style.Resources> <Style.Triggers> <Trigger Property="IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard Storyboard="{StaticResource press}"/> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard Storyboard="{StaticResource hover}"/> </Trigger.ExitActions> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Trigger.EnterActions> <BeginStoryboard Storyboard="{StaticResource hover}"/> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard Storyboard="{StaticResource leave}"/> </Trigger.ExitActions> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> </StackPanel> </Grid> </Window>
需求
- 按钮默认尺寸为100x45;
- 鼠标悬停时,动画将按钮尺寸改为120x45(宽度增加20),离开时恢复;
- 鼠标按下时,动画将尺寸改为125x50(宽高各增加5),松开时恢复。
解决方案
问题原因
鼠标悬停时IsMouseOver触发器的动画已经启动,此时点击按钮触发IsPressed动画时,WPF不会自动终止正在运行的同属性动画,导致新动画无法覆盖生效。此外,虽然IsPressed优先级高于IsMouseOver,但无显式停止操作的话,新动画无法正常启动。
修正方案
- 给每个
BeginStoryboard添加Name属性,方便在触发器中定位并停止其他动画; - 在
IsPressed的EnterActions中先停止hover动画,再启动press动画;在ExitActions中停止press动画,再重启hover动画; - 确保动画结束后保持最终值(默认
FillBehavior="HoldEnd",可显式声明)。
修正后的XAML代码
<Window x:Class="TestWpf.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:TestWpf" mc:Ignorable="d" Title="MainWindow" Height="320" Width="340"> <Window.Resources> <QuadraticEase x:Key="easing" EasingMode="EaseOut"/> </Window.Resources> <Grid> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"> <Label Name="label"/> <Button Content="Hello" Width="100" Height="45"> <Button.Style> <Style TargetType="Button"> <Style.Resources> <Storyboard x:Key="press"> <DoubleAnimation Storyboard.TargetProperty="Width" To="125" Duration="0:0:0.100" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="50" Duration="0:0:0.100" EasingFunction="{StaticResource easing}"/> </Storyboard> <Storyboard x:Key="hover"> <DoubleAnimation Storyboard.TargetProperty="Width" To="120" Duration="0:0:0.200" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="45" Duration="0:0:0.200" EasingFunction="{StaticResource easing}"/> </Storyboard> <Storyboard x:Key="leave"> <DoubleAnimation Storyboard.TargetProperty="Width" To="100" Duration="0:0:0.300" EasingFunction="{StaticResource easing}"/> <DoubleAnimation Storyboard.TargetProperty="Height" To="45" Duration="0:0:0.300" EasingFunction="{StaticResource easing}"/> </Storyboard> </Style.Resources> <Style.Triggers> <Trigger Property="IsPressed" Value="True"> <Trigger.EnterActions> <StopStoryboard BeginStoryboardName="hoverStoryboard"/> <BeginStoryboard x:Name="pressStoryboard" Storyboard="{StaticResource press}"/> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="pressStoryboard"/> <BeginStoryboard x:Name="hoverStoryboardAfterPress" Storyboard="{StaticResource hover}"/> </Trigger.ExitActions> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Trigger.EnterActions> <BeginStoryboard x:Name="hoverStoryboard" Storyboard="{StaticResource hover}"/> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="hoverStoryboard"/> <StopStoryboard BeginStoryboardName="hoverStoryboardAfterPress"/> <BeginStoryboard Storyboard="{StaticResource leave}"/> </Trigger.ExitActions> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> </StackPanel> </Grid> </Window>
额外说明
- 使用
StopStoryboard终止正在运行的同属性动画,确保新动画能正常启动; - 松开按钮时,先停止
press动画再启动hover动画,保证回到悬停状态的尺寸; - 鼠标离开时,停止所有悬停相关动画,再启动恢复默认尺寸的动画,避免状态冲突。
内容的提问来源于stack exchange,提问作者SlimeNull
相关产品推荐
相关产品推荐

