结合WPF DataTriggers和故事板在code [英] Combining WPF DataTriggers and Storyboard in code

查看:182
本文介绍了结合WPF DataTriggers和故事板在code的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(这是为了解决<一个企图href=\"http://stackoverflow.com/questions/5826828/how-to-start-stop-animation-in-user-control-from-view-model\">my以不同的方式较早问题的。)

我创建它使用我希望能够通过我的视图模型设置属性动画一个一个画笔的用户控件。梯度刷也有绑定到视图模型的一些属性。

I've created a user control which uses a RadialGradientBrush that I would like to be able to animate by setting a property on my view model. The gradient brush also has some properties that are bound to the view model.

该XAML的用户控件(某些属性剪断为简洁起见):

The XAML for the user control is (some properties snipped for brevity):

<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>

在code-背后设置了不同的依赖属性,并在控件的Loaded事件,定义了一个故事板动画画笔的中心和渐变原点属性,然后定义应的一个值响应DataTriggers那些依赖属性:

The code-behind sets up the various dependency properties, and in the control's Loaded event, defines a Storyboard to animate the RadialGradientBrush's Center and GradientOrigin properties, and then defines the DataTriggers that should respond to the value of one of those dependency properties:

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大火的第一次,我得到以下异常:

When I try to run the project, it compiles successfully and the window loads successfully with the control in its default state. However, when the DataTrigger fires for the first time, I get the following exception:

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

我已经附加一个样本项目证明什么,我试图实现

推荐答案

它看起来像你需要使用的 Style.RegisterName 。是这样的:

It looks like you'd need to register the name of your BeginStoryboard using Style.RegisterName. Something like:

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

有关动画/故事板,你实际上试图在AnimatedLineArrow(而不是实际的放射)动画画笔属性。你要么需要故事板的目标设定为画笔或露出AnimatedLineArrow,你可以动画另一个属性。

For your animation/storyboard, you are effectively trying to animate the RadialGradientBrush properties on the AnimatedLineArrow (not on the actual RadialGradientBrush). You'd either need to set the storyboard target to the RadialGradientBrush or expose another property on AnimatedLineArrow that you can animate.

是这样的:

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,你需要使用:

Then in your AnimatedLineArrow.xaml, you'd need to use:

<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>

这篇关于结合WPF DataTriggers和故事板在code的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆