WPF XAML Trigger中使用动画后 动画对象冻结的处理办法
在编写XAML时
在Trigger中使用动画,在动画之后,动画对象就会被冻结,无法被其他动画或者属性改变。
处理办法有:
1 使用附加属性来添加动画
public static readonly DependencyProperty AniInvokePropery = DependencyProperty.RegisterAttached("AniInvoke", typeof(Storyboard), typeof(ATCH), new PropertyMetadata(null, AniInvokeCallBack)); public static void SetAniInvoke(DependencyObject d, Storyboard value) => d.SetValue(AniInvokePropery, value); public static Storyboard GetAniInvoke(DependencyObject d) => (Storyboard)d.GetValue(AniInvokePropery); private static void AniInvokeCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) { var t = d as FrameworkElement; var s = (Storyboard)e.NewValue; if (s != null) t.BeginStoryboard(s); }
xaml
<Button Height="128" > <local:ATCH.AniInvoke> <Storyboard> <Storyboard > <DoubleAnimation From="20" To="300" Duration="0:0:01" Storyboard.TargetProperty="Width" /> </Storyboard> </Storyboard> </local:ATCH.AniInvoke> </Button>
如果是想要搭配trigger来使用则是需要:
<Button Height="128" > <Button.Resources> <Storyboard x:Key="x"> <DoubleAnimation From="20" To="300" Duration="0:0:01" Storyboard.TargetProperty="Width" /> </Storyboard> </Button.Resources> <Button.Style> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="local:ATCH.AniInvoke" Value="{StaticResource x}"/> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button>
2 依赖属性来增加动画
依赖属性相对附加属性而言,在MVVM模式也是非常的引用
public static readonly DependencyProperty AniInvokeProperty= DependencyProperty.Register("AniInvoke", typeof(Storyboard), typeof(SearchViewPage), new PropertyMetadata(null, AniInvokeCallBack)); private static void AniInvokeCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) { var b = d as SearchViewPage; var s = (Storyboard)e.NewValue; if(s!=null) b.BeginStoryboard(s); }
xaml( 涉及其他代码,只是截取部分,这个部分是style的trigger)
<DataTrigger Binding="{Binding ElementName=SearchBox,Path=Tag}" Value="false"> <Setter Property="Tag" Value="T1"/> <Setter Property="AniInvoke"> <Setter.Value> <Storyboard> <DoubleAnimation From="220" To="440" Duration="0:0:00.5" Storyboard.TargetProperty="Width"/> </Storyboard> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding ElementName=SearchBox,Path=Tag}" Value="true"> <Setter Property="Tag" Value="T2"/> <Setter Property="AniInvoke"> <Setter.Value> <Storyboard> <DoubleAnimation From="440" To="220" Duration="0:0:00.5" Storyboard.TargetProperty="Width"/> </Storyboard> </Setter.Value> </Setter> </DataTrigger>
3使用storybroad的FillBehavior
FillBehavior有两个值一个是Stop和HoldEnd
HoldEnd是默认值,也就是维持动画结束后的状态
Stop则是取消动画后的状态
启用stop后 在其他地方设置width时是可以改变的,具体看依赖属性的优先级
<Button Height="128" Width="150"> <Button.Resources> <Storyboard x:Key="x" > <DoubleAnimation From="30" To="150" Duration="0:0:01" FillBehavior="Stop" Storyboard.TargetProperty="Width" /> </Button.Resources> <Button.Style> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="IsMouseOver" Value="false"> <Trigger.EnterActions> <BeginStoryboard Name="s1" Storyboard="{StaticResource x}"> </BeginStoryboard> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button>
4通过情节动画的StopStoryboard来停止动画
这个则是需要使用其他的触发器配合或者是使用EnterActions和ExitActions的方式
EnterActions是触发器活跃时启动的方法,也就是触发器触发时
ExitActions是触发器不活跃时启动,注意不活跃是本触发器活跃后或者触发条件为相反时
(1)其他触发器配合:
<Button x:Name="btn1" Height="128" Width="300"> <Button.Resources> <Storyboard x:Key="x1"> <DoubleAnimation From="300" To="20" Duration="0:0:01" Storyboard.TargetProperty="Width" /> </Storyboard> </Button.Resources> <Button.Style> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard x:Name="bs2" Storyboard="{StaticResource x1}"> </BeginStoryboard> </Trigger.EnterActions> </Trigger> <Trigger Property="IsPressed" Value="false"> <Trigger.EnterActions> <StopStoryboard BeginStoryboardName="bs2"/> </Trigger.EnterActions> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> <TextBlock FontSize="20" Margin="46,292,171,57"> <Run>点击状态:</Run> <Run Text="{Binding ElementName=btn1, Path=IsPressed,Mode=OneWay}"></Run> </TextBlock>
注意鼠标要在触发区域内
(2)通过EnterAction和ExitAction
<Button x:Name="btn1" Height="128" Width="300"> <Button.Resources> <Storyboard x:Key="x1"> <DoubleAnimation From="300" To="20" Duration="0:0:01" FillBehavior="HoldEnd" Storyboard.TargetProperty="Width" /> </Storyboard> </Button.Resources> <Button.Style> <Style TargetType="Button"> <Style.Triggers> <Trigger Property="IsPressed" Value="True"> <Trigger.EnterActions> <BeginStoryboard x:Name="bs2" Storyboard="{StaticResource x1}"> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <StopStoryboard BeginStoryboardName="bs2"/> </Trigger.ExitActions> </Trigger> </Style.Triggers> </Style> </Button.Style> </Button> <TextBlock FontSize="20" Margin="46,292,171,57"> <Run>点击状态:</Run> <Run Text="{Binding ElementName=btn1, Path=IsPressed,Mode=OneWay}"></Run> </TextBlock>