在代码中组合WPF DataTriggers和Storyboard

时间:2011-05-02 23:56:24

标签: wpf binding

(这是尝试以不同的方式解决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事件中定义一个Storyboard来为RadialGradientBrush的Center和GradientOrigin属性设置动画,然后定义应该响应其中一个依赖项属性值的DataTriggers :

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

1 个答案:

答案 0 :(得分:2)

您似乎需要使用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>