WPF XAML Trigger中使用动画后 动画对象冻结的处理办法

Posted lonelyxmas

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF XAML Trigger中使用动画后 动画对象冻结的处理办法相关的知识,希望对你有一定的参考价值。

原文: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>
技术图片

技术图片

以上是关于WPF XAML Trigger中使用动画后 动画对象冻结的处理办法的主要内容,如果未能解决你的问题,请参考以下文章

WPF C#实现动画(速度启停缓动线性渐变)

如何在 UWP 使用 wpf 的 Trigger

荐牛逼的WPF动画库:XamlFlair

如何在 WPF / XAML 项目中使用 Rive 动画?

WPF 内部Template 动画板 无法冻结此 Storyboard 时间线树供跨线程使用

WPF 内部Template 动画板 无法冻结此 Storyboard 时间线树供跨线程使用