【问题标题】:Combining WPF DataTriggers and Storyboard in code在代码中结合 WPF DataTriggers 和 Storyboard
【发布时间】:2011-05-04 19:26:59
【问题描述】:

(这是尝试以不同的方式解决my earlier problem。)

我创建了一个使用 RadialGradientBrush 的用户控件,我希望能够通过在我的视图模型上设置属性来制作动画。渐变画笔也有一些绑定到视图模型的属性。

用户控件的 XAML 是(为简洁起见,剪掉了一些属性):

<UserControl x:Class="WpfApplication1.AnimatedLineArrow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:Controls="clr-namespace:Microsoft.Expression.Controls;assembly=Microsoft.Expression.Drawing"
             mc:Ignorable="d" d:DesignHeight="150" d:DesignWidth="300"
             Name="animatedLineArrow">
    <Grid>
        <Controls:LineArrow x:Name="ArrowControl"
            StartCorner="{Binding ElementName=animatedLineArrow, Path=StartCorner, FallbackValue=TopRight}"
            Width="{Binding ElementName=animatedLineArrow, Path=Width, FallbackValue=200}"
            Height="{Binding ElementName=animatedLineArrow, Path=Height, FallbackValue=200}"
            <Controls:LineArrow.Stroke>
                <RadialGradientBrush RadiusX="0.2" RadiusY="1.0" 
                                     Center="{Binding ElementName=animatedLineArrow, Path=StartPoint, Mode=OneWay}"
                                     GradientOrigin="{Binding ElementName=animatedLineArrow, Path=StartPoint, Mode=OneWay}">
                    <RadialGradientBrush.GradientStops>
                        <GradientStop Color="{Binding ElementName=animatedLineArrow, Path=HighlightColour, Mode=OneWay, FallbackValue=Cyan}" Offset="0.0" />
                        <GradientStop Color="{Binding ElementName=animatedLineArrow, Path=PrimaryColour, Mode=OneWay, FallbackValue=Navy}" Offset="1.0" />
                    </RadialGradientBrush.GradientStops>
                </RadialGradientBrush>
            </Controls:LineArrow.Stroke>
        </Controls:LineArrow>
    </Grid>
</UserControl>

代码隐藏设置了各种依赖属性,并在控件的 Loaded 事件中定义了一个故事板来为 RadialGradientBrush 的 Center 和 GradientOrigin 属性设置动画,然后定义应该响应这些依赖属性之一的值的 DataTrigger :

private void ConfigureAnimation(object sender, EventArgs e)
{
    StartPoint = StartingPoints[StartCorner];
    EndPoint = EndingPoints[StartCorner];

    AnimatedLineArrow arrow = (AnimatedLineArrow)sender;
    Storyboard storyboard = CreateStoryboard(arrow);

    DataTrigger startTrigger = new DataTrigger
                                   {
                                       Binding = new Binding
                                                     {
                                                         Path = new PropertyPath(IsRunningProperty),
                                                         RelativeSource = RelativeSource.Self
                                                     },
                                       Value = true
                                   };
    startTrigger.EnterActions.Add(new BeginStoryboard { Storyboard = storyboard, Name = "beginStoryboard" });

    DataTrigger endTrigger = new DataTrigger
                                 {
                                     Binding = new Binding
                                                   {
                                                       Path = new PropertyPath(IsRunningProperty),
                                                       RelativeSource = RelativeSource.Self
                                                   },
                                     Value = false
                                 };
    endTrigger.EnterActions.Add(new StopStoryboard { BeginStoryboardName = "beginStoryboard" });

    Style style = new Style(typeof(AnimatedLineArrow));
    style.Triggers.Add(startTrigger);
    style.Triggers.Add(endTrigger);
    arrow.Style = style;
}

private Storyboard CreateStoryboard(AnimatedLineArrow arrow)
{
    Storyboard storyboard = new Storyboard();

    PointAnimation originAnimation = new PointAnimation(StartingPoints[StartCorner], EndingPoints[StartCorner], Duration, FillBehavior.HoldEnd);
    PointAnimation centreAnimation = originAnimation.Clone();

    Storyboard.SetTarget(originAnimation, arrow);
    Storyboard.SetTargetProperty(originAnimation, new PropertyPath(RadialGradientBrush.GradientOriginProperty));

    Storyboard.SetTarget(centreAnimation, arrow);
    Storyboard.SetTargetProperty(centreAnimation, new PropertyPath(RadialGradientBrush.CenterProperty));

    storyboard.Children.Add(originAnimation);
    storyboard.Children.Add(centreAnimation);
    return storyboard;
}

当我尝试运行项目时,它编译成功,并且窗口成功加载,控件处于默认状态。但是,当 DataTrigger 第一次触发时,我得到以下异常:

System.InvalidOperationException was unhandled
  Message='beginStoryboard' name cannot be found in the name scope of 'System.Windows.Style'.
  Source=PresentationFramework

我附上了一个示例项目to demonstrate what I am trying to achieve

【问题讨论】:

    标签: wpf binding


    【解决方案1】:

    您似乎需要使用 Style.RegisterName 注册 BeginStoryboard 的名称。比如:

    //...
    BeginStoryboard bs = new BeginStoryboard { Storyboard = storyboard, Name = "beginStoryboard" };
    startTrigger.EnterActions.Add(bs);
    //...
    style.RegisterName(bs.Name, bs);
    

    对于您的动画/故事板,您实际上是在尝试为 AnimatedLineArrow(而不是实际的 RadialGradientBrush)上的 RadialGradientBrush 属性设置动画。您要么需要将情节提要目标设置为 RadialGradientBrush,要么在 AnimatedLineArrow 上公开另一个您可以制作动画的属性。

    类似:

    public static readonly DependencyProperty AnimatedPointProperty = DependencyProperty.Register("AnimatedPoint",
        typeof(Point), typeof(AnimatedLineArrow), new FrameworkPropertyMetadata(new Point()));
    
    public Point AnimatedPoint {
        get { return (Point)this.GetValue(AnimatedLineArrow.AnimatedPointProperty); }
        set { this.SetValue(AnimatedLineArrow.AnimatedPointProperty, value); }
    }
    
    private Storyboard CreateStoryboard(AnimatedLineArrow arrow)
    {
        Storyboard storyboard = new Storyboard();
    
        PointAnimation originAnimation = new PointAnimation(StartingPoints[StartCorner], EndingPoints[StartCorner], Duration, FillBehavior.HoldEnd);
        Storyboard.SetTarget(originAnimation, arrow);
        Storyboard.SetTargetProperty(originAnimation, new PropertyPath(AnimatedPointProperty));
        storyboard.Children.Add(originAnimation);
        return storyboard;
    }
    

    然后在您的 AnimatedLineArrow.xaml 中,您需要使用:

    <RadialGradientBrush RadiusX="0.2" RadiusY="1.0" 
                            Center="{Binding ElementName=animatedLineArrow, Path=StartPoint, Mode=OneWay}"
                            GradientOrigin="{Binding ElementName=animatedLineArrow, Path=AnimatedPoint, Mode=OneWay}">
        <RadialGradientBrush.GradientStops>
            <GradientStop Color="{Binding ElementName=animatedLineArrow, Path=HighlightColour, Mode=OneWay, FallbackValue=Cyan}" Offset="0.0" />
            <GradientStop Color="{Binding ElementName=animatedLineArrow, Path=PrimaryColour, Mode=OneWay, FallbackValue=Navy}" Offset="1.0" />
        </RadialGradientBrush.GradientStops>
    </RadialGradientBrush>
    

    【讨论】:

    • 非常感谢@CodeNaked 的提示。它当然会处理 DataTrigger 触发时生成的 IOE。然而,动画仍然没有发生——你有什么想法吗?
    • 我已经尝试删除所有数据触发器的内容,并在完成设置后才启动情节提要,但仍然没有动画。这表明问题在于我如何设置故事板及其动画。
    • 再次感谢@CodeNaked。动画现在可以工作了,DataTriggers 也可以停止和启动动画。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-19
    • 2018-07-21
    • 1970-01-01
    • 2016-12-26
    • 2014-08-27
    • 2013-04-23
    • 1970-01-01
    相关资源
    最近更新 更多