在代码中组合 WPF DataTriggers 和 Storyboard

2024-01-10

(这是试图解决我之前的问题 https://stackoverflow.com/questions/5826828/how-to-start-stop-animation-in-user-control-from-view-model以不同的方式。)

我创建了一个使用 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 属性设置动画,然后定义应响应这些依赖属性之一的值的 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

我附上了一个示例项目展示我想要实现的目标 http://dl.dropbox.com/u/8139802/WpfAnimatedArrow.zip.


看起来您需要使用以下命令注册 BeginStoryboard 的名称样式.寄存器名称 http://msdn.microsoft.com/en-us/library/system.windows.style.registername.aspx。就像是:

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

对于您的动画/故事板,您实际上是在尝试为 AnimatedLineArrow(而不是实际的 RadialGradientBrush)上的 RadialGradientBrush 属性设置动画。您需要将 Storyboard 目标设置为 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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在代码中组合 WPF DataTriggers 和 Storyboard 的相关文章

随机推荐

  • 如何在 R 中重置 par(mfrow)

    我设置了 par mfrow c 1 2 现在每次我绘制它时 它都会显示将其分成 2 个图 我怎样才能将其重置为仅显示一个图 非常感谢 您可以重置 mfrow 参数 par mfrow c 1 1
  • 阻止垃圾邮件发送者创建帐户(reCaptcha 不起作用)

    您好 我们刚刚在我们的电子邮件系统中注意到一堆尼日利亚垃圾邮件帐户 现在 我们的注册表单中确实有一个 reCaptcha 但显然他们手动或以其他方式绕过了它 这似乎是一种半手动规避 因为帐户不是批量创建的 而是以中间间隔几分钟的方式源源不断
  • enable_if:不带参数的 void 成员函数的最小示例

    我正在努力更好地理解std enable if在 C 11 中 并一直在尝试编写一个最小的示例 一个类A具有成员函数void foo 根据类型有不同的实现T来自类模板 下面的代码给出了所需的结果 但我还没有完全理解它 为什么版本V2工作 但
  • Double 数据类型,计算小数位后的小数

    下面的方法应该返回 这个 双精度 值有多少小数精度 尾随数字的数量 的答案 当值看起来像 5900 43 5900 043 等等时 我就猜对了 当该方法收到 5900 00 时 它返回 0 这是错误的 在我的需要中
  • 从单独的线程访问表单的控件

    我正在练习线程并遇到这个问题 情况是这样的 我在一个表单上有 4 个进度条 一个用于下载文件 一个用于显示页面加载状态等 我必须从单独的线程控制每个 ProgressBar 的进度 问题是我得到了无效操作异常其中说 跨线程操作无效 控制 p
  • 按引用传递引用与按值传递引用 - C#

    问候 我明白了按值传递和按引用传递之间的区别 但是通过 ref 传递引用 例如数组 和通过值传递数组是我似乎无法理解的 如何通过引用传递引用 int myArray 1 2 3 PassByVal myArray PassByRef ref
  • 什么时候不应该使用 React 备忘录?

    我一直在玩React 16 6 0最近我喜欢这个想法反应备忘录 但我一直无法找到有关最适合实现它的场景的任何内容 React 文档 https reactjs org docs react api html reactmemo https
  • 使用后置变量传递表数据

    基本上我有一个表 其中包含来自数据库的一堆数字 其中包含总计 小计列 我不打算将任何总数添加到数据库中 但我需要将总数从一页传递到下一页 我似乎无法使用 PHP 将它们作为后置变量正确传递 我想知道这是否是一个糟糕的策略 其次我应该做什么
  • 如何为角度反应形式的自定义验证器编写单元测试用例?

    我有一个自定义模型驱动的表单验证器来验证最大文本长度 export function maxTextLength length string return function control FormControl const maxLeng
  • 如何使用 Spring Data JPA 和 Hibernate 执行 H2 存储过程?

    我想使用 Spring Data JPA 和 Hibernate 来执行一个简单的 H2 数据库存储过程 存储过程类 public class H2StoredProcedures public static String stringIn
  • Java 正则表达式 (?i) 与 Pattern.CASE_INSENSITIVE

    我在用着 b w W 1 b 随着input input replaceAll regex 1 查找字符串中的重复单词并删除重复项 例如 字符串输入 for for for 将变为 for 然而 即使我使用过 它也无法将 Hello hel
  • @Value 变量在使用 @TestPropertySource 的单元测试中为 NULL

    在下面的单元测试中 我手动提供属性并尝试从现有的 YAML 资源文件中读取它们 尝试了不同的策略 TestPropertySource the Value 属性未设置 我总是为它们获取 NULL SpringBootConfiguratio
  • 当我在 flutter 应用程序中切换 appbar 时,如何使 webview 不重新加载?

    我希望当我在 flutter 应用程序中切换 appbar 时 webview 不重新加载 但我不知道该怎么做 很抱歉我是初学者 这是我录制的gif I searched on Google but I didn t find an ans
  • Excel vba - 禁用鼠标事件

    我正在开发一个Excel 2010工作簿 处于手动公式计算模式 文件 gt 选项 gt 公式 gt 工作簿计算 gt 手册 但是 我想要一些菜单选项来导致工作簿的重新计算 所以我使用以下代码 Private Sub Worksheet Ch
  • 突出显示 SWT 树节点中的特定字符串

    我有一个要求 首先要加载树 树包含 4 个级别 有一个文本字段 用户可以在其中输入 filterText 然后可以按搜索按钮 在树中 在四个级别中的任何一个中 如果与过滤器文本匹配 则该特定字符串仅应以黄色突出显示 而不是整个节点及其相应的
  • 如何阻止固定对象超出其父容器?

    我目前正在为学校制作一个网站 在该网站上我有一个带有链接的侧边栏 我希望它在侧面的任何地方都可见 所以我使用了position fixed 但现在它不再保留在其父级的空间内 而是从页面的最顶部开始 h1 text align center
  • 是否有一种校验和算法也支持从中“减去”数据?

    我有一个包含大约 1 亿个文档的系统 我想跟踪它们在镜像之间的修改 为了有效地交换有关修改的信息 我想按天发送有关修改文档的信息 而不是按每个单独的文档发送 像这样的事情 2012 03 26 cs26 2012 03 25 cs25 20
  • Android - 延迟加载图像

    我正在尝试伪造某种进度条 我有 X 张图片并想要一张ImageView以一定的延迟向他们展示 我尝试过做这样的事情 for i 2 i
  • 关于如何正确重写 object.GetHashCode() 的一般建议和指南

    根据MSDN http msdn microsoft com en us library system object gethashcode aspx 哈希函数必须具有以下属性 如果两个对象比较相等 则每个对象的 GetHashCode 方
  • 在代码中组合 WPF DataTriggers 和 Storyboard

    这是试图解决我之前的问题 https stackoverflow com questions 5826828 how to start stop animation in user control from view model以不同的方式