在WPF中更改样式时,故事板不会更改

时间:2016-06-14 09:06:26

标签: .net wpf xaml wpf-style wpf-animation

我想在箭头图片(png)上运行一个简单的动画。箭头指向下方或向上,动画应该是指向它所指向的方向的箭头。

我使用Image控件并为其指定两种样式之一。这些样式定义了要使用的图片和故事板中的三个双动画。动画应该无条件地运行,就在图像创建的那一刻,永远。其中一种样式是向上箭头向上移动的箭头( Trend_Rising ),另一种样式是向下箭头指向下方的波形( Trend_Falling )。< / p>

以下是图像,并且样式位于从嵌入图像的UserControl引用的单独文件中。

<Image x:Name="TrendImg" Style="{DynamicResource Trend_Falling}" />

这是样式文件的内容:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

     <Style x:Key="Trend_Base" TargetType="Image">

        <Setter Property="OpacityMask">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="Black" />
                    <GradientStop Color="Transparent" />
                    <GradientStop Color="Black" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>

    </Style>

    <Style x:Key="Trend_Rising_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}">

        <Style.Triggers>
            <Trigger Property="IsVisible" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0"  To="1.0" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1"  To="1.1" Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers>

    </Style>

    <Style x:Key="Trend_Falling_Base" TargetType="Image" BasedOn="{StaticResource Trend_Base}">

        <Style.Triggers>
            <Trigger Property="IsVisible" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0"  Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1"  Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers>

    </Style>

    <Style x:Key="Trend_Rising" TargetType="Image" BasedOn="{StaticResource Trend_Rising_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_rising.png" />
    </Style>

    <Style x:Key="Trend_Falling" TargetType="Image" BasedOn="{StaticResource Trend_Falling_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_falling.png" />
    </Style>

</ResourceDictionary>

当我以编程方式更改样式时,动画不会改变。例如,如果我启动应用程序(图像分配了 Trend_Falling 样式),将显示向下箭头,波形动画向下移动。但是当我在运行时将样式更改为 Trend_Rising 时,箭头图片会按原样更改,但动画保持不变。

TrendImg.SetResourceReference(Control.StyleProperty, "Trend_Rising")

我做错了什么?我将不胜感激任何帮助。谢谢!

- 编辑 -

我创建了一个 ImageWithAnim 类,它是 Image 的后代,并为其添加了一个布尔 Animate 依赖项属性。然后我将触发器附加到该属性而不是 IsVisible 。 True启动故事板,false应该停止它,但它不会...当我将 Animate 设置为false时,会抛出一个异常,说明名称​​ RisingStoryboard 可以不能在命名空间 System.Windows.Style 中解析。我在StackOverflow上找到了几个帖子,根据这个帖子,这个例子应该可以工作(在声称它不会:-)的那些帖子中。

所以......现在我不知道怎么做对了。我将不胜感激任何帮助。谢谢!

这是更改的xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Test="clr-namespace:StyleChangeTest">

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim">

        <Setter Property="OpacityMask">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="Black" />
                    <GradientStop Color="Transparent" />
                    <GradientStop Color="Black" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>

    </Style>

    <Style x:Key="Trend_Rising_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}">

        <Style.Triggers>
            <Trigger Property="Animate" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="RisingStoryboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0"  To="1.0" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1"  To="1.1" Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>

            <Trigger Property="Animate" Value="False">
                <Trigger.EnterActions>
                    <StopStoryboard BeginStoryboardName="RisingStoryboard" />
                </Trigger.EnterActions>
            </Trigger>
        </Style.Triggers>

    </Style>

    <Style x:Key="Trend_Falling_Base" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}">

        <Style.Triggers>
            <Trigger Property="Animate" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="FallingStoryboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0"  Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1"  Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>
            </Trigger>

            <Trigger Property="Animate" Value="False">
                <Trigger.EnterActions>
                    <StopStoryboard BeginStoryboardName="FallingStoryboard" />
                </Trigger.EnterActions>
            </Trigger>                
        </Style.Triggers>

    </Style>

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Rising_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_rising.png" />
    </Style>

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Falling_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_falling.png" />
    </Style>

</ResourceDictionary>

这是 ImageWithAnim 类:

Public Class ImageWithAnim
    Inherits Image

    Private Shared _animate As DependencyProperty = DependencyProperty.Register("Animate",
                                                                                GetType(Boolean),
                                                                                GetType(ImageWithAnim),
                                                                                New PropertyMetadata(defaultValue:=False))

    Public Shared ReadOnly Property AnimateProperty As DependencyProperty
        Get
            Return _animate
        End Get
    End Property

    Public Property Animate() As Boolean
        Get
            Return CBool(GetValue(_animate))
        End Get
        Set(value As Boolean)
            SetValue(_animate, value)
        End Set
    End Property

End Class

1 个答案:

答案 0 :(得分:1)

巧合的是,我刚刚找到了自己问题的答案。故事板的名称无法解析,因为它们是在基本样式中定义的。当我直接在我感兴趣的两种风格中定义它们时,我可以按预期使用 ImageWithAnim Animate 属性启动和停止它们,没有任何例外。

因此,在更改图像样式时,我必须执行以下操作:

TrendImg.Animate = False
TrendImg.SetResourceReference(ImageWithAnim.StyleProperty, "Trend_Falling")
TrendImg.Animate = True

现在动画被正确更改,波浪动画按箭头指向的方向移动,这就是我想要实现的目标。

以下是改变后的风格:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Test="clr-namespace:StyleChangeTest">

    <Style x:Key="Trend_Base" TargetType="Test:ImageWithAnim">

        <Setter Property="OpacityMask">
            <Setter.Value>
                <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                    <GradientStop Color="Black" />
                    <GradientStop Color="Transparent" />
                    <GradientStop Color="Black" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>

    </Style>

    <Style x:Key="Trend_Rising" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_rising.png" />

        <Style.Triggers>
            <Trigger Property="Animate" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="RisingStoryboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="-0.1" To="0.9" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="0.0"  To="1.0" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="0.1"  To="1.1" Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>

                <Trigger.ExitActions>
                    <StopStoryboard BeginStoryboardName="RisingStoryboard" />
                </Trigger.ExitActions>
            </Trigger>
        </Style.Triggers>
    </Style>

    <Style x:Key="Trend_Falling" TargetType="Test:ImageWithAnim" BasedOn="{StaticResource Trend_Base}">
        <Setter Property="Height" Value="16" />
        <Setter Property="Source" Value="trend_falling.png" />

        <Style.Triggers>
            <Trigger Property="Animate" Value="True">
                <Trigger.EnterActions>
                    <BeginStoryboard x:Name="FallingStoryboard">
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[0].Offset" From="0.9" To="-0.1" Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[1].Offset" From="1.0" To="0.0"  Duration="0:0:2" RepeatBehavior="Forever" />
                            <DoubleAnimation Storyboard.TargetProperty="OpacityMask.GradientStops[2].Offset" From="1.1" To="0.1"  Duration="0:0:2" RepeatBehavior="Forever" />
                        </Storyboard>
                    </BeginStoryboard>
                </Trigger.EnterActions>

                <Trigger.ExitActions>
                    <StopStoryboard BeginStoryboardName="FallingStoryboard" />
                </Trigger.ExitActions>
            </Trigger>
        </Style.Triggers>
    </Style>

</ResourceDictionary>

并解释为什么我在开始时将故事板放在基本样式中。问题是,在我的原始应用程序中,我有几个不同的箭头图片,并且只是不想重复故事板定义。但似乎我必须这样做。