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

Storyboard does not change when I change style in WPF

我想 运行 箭头图片 (png) 上的简单动画。箭头指向下方或上方,动画应该是波浪朝箭头指向的方向移动。

我使用 Image 控件并将两种样式之一分配给它。这些样式定义了故事板中要使用的图片和三个双动画。动画应该无条件地 运行,从图像创建的那一刻起,永远。其中一种样式是箭头向上,波浪向上移动(Trend_Rising),另一种样式是箭头向下,波浪向下移动(Trend_Falling).

以下是图像,样式位于从嵌入图像的 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 class,它是 Image 的后代,并添加了一个布尔值 Animate 对它的依赖 属性。然后我将触发器附加到 属性 而不是 IsVisible。 True 启动情节提要,而 false 应该停止它,但它没有...当我将 Animate 设置为 false 时,会抛出一个异常,说明名称 RisingStoryboard 无法在命名空间 System.Windows.Style 中解析。我在 Whosebug 上找到了几篇帖子,根据这些帖子,这个例子应该可以工作(在那些声称它不会 :-) 的帖子中)。

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

这是修改后的 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 class:

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

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

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

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>

并解释为什么我在开头将故事板置于基本样式中。问题是在我原来的应用程序中我有几个不同的箭头图片,只是不想重复情节提要定义。但是看来我不得不。