【问题标题】:WPF Animate double property changesWPF Animate 双属性更改
【发布时间】:2014-05-07 22:54:54
【问题描述】:

我正在尝试找到一种通用方式来在每次更新 double 类型的属性时运行动画。

这必须是适用于所有双精度值的单一解决方案。这意味着我不想为每个UIElement 属性写一个专有的AttachedProperty(一个用于Opacity,另一个用于Height)。

我想要完成的一个伪示例:

<TextBlock x:Name="pageTitle" Text="title example" attached:AnimatedPropertyPath="(UIElement.Opacity)" Opacity="{Binding Path=TitleOpacity}" />

附加的属性应该监听不透明度的任何变化,取消它并运行一个动画,让它逐渐变化。

我的问题:

  1. 这种确切的语法有意义吗?可行吗?
  2. 有没有办法通过绑定取消 Opacity 属性立即更改并改为运行动画?
  3. 任何指向示例的链接都将受到高度赞赏,因为我自己找不到任何链接。

我想避免使用 DataTriggers,因为它需要太多的 xaml。最好将其嵌入为附加属性,就像上面的 peudo xaml 一样。

【问题讨论】:

  • 是的,这是可行的。您为您的TextBlock 创建一个Style,然后在该Style 中创建DataTriggers,然后您可以使用DataTrigger.EnterActionDataTrigger.ExitAction,或者如果您需要更灵活的方法,请创建Converter 来处理你的TextBlock
  • 我不想使用 DataTrigger.EnterAction 因为它太麻烦了。我希望它尽可能自动化,而不必在 xaml 中连接数十行来让这样一个简单的想法发挥作用。
  • 您需要编辑您的帖子,因为您声明“我不想编写专有的 AttachedProperty”,然后您写道“最好将其嵌入为附加属性”。你需要做出决定。
  • 已编辑。我的意思是我不想为每个 UIElement 属性编写单独的附加属性。一个能够处理所有事情的人就可以了。
  • kk,我知道当我写我的Style 时,我将它设置为最小公分母,即frameworkElement,然后我使用DataTriggers 来处理这种行为。 提示 Style 将应用于 xaml 中的每个控件,如果您像这样声明它&lt;Style x:Key="{x:Type FrameworkElement}" TargetType="{x:Type FrameworkElement}"&gt;//your markup here &lt;/Style 不需要很多行。一旦声明,它将应用于每个 FrameworkElement。

标签: wpf attached-properties wpf-animation


【解决方案1】:

我的问题:

  • 这种确切的语法有意义吗?可行吗?

它必须是附加属性吗?使用 Behavior 可以吗?

  • 有没有办法通过绑定取消 Opacity 属性立即更改并改为运行动画?

也许有一些技巧(据我所知没有)。再次,这是必须拦截和取消正常 DP 操作的必要条件吗?

  • 任何指向示例的链接都将受到高度赞赏,因为我自己找不到任何链接。

如果你能稍微调整一下你的要求,我可以举个例子:

因此,如果您的要求是在绑定到值更改时为任何 double DP 设置动画,我们可以使用 Behavior

public class AnimateBehavior : Behavior<UIElement> {
  public static readonly DependencyProperty ToAnimateProperty =
    DependencyProperty.Register("ToAnimate", typeof(DependencyProperty),
      typeof(AnimateBehavior), new FrameworkPropertyMetadata(null));

  public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(double),
      typeof(AnimateBehavior),
      new FrameworkPropertyMetadata(0.0d, FrameworkPropertyMetadataOptions.None, ValueChangedCallback));

  public DependencyProperty ToAnimate {
    get { return (DependencyProperty) GetValue(ToAnimateProperty); }
    set { SetValue(ToAnimateProperty, value); }
  }

  public double Value {
    get { return (double) GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
  }

  private static void ValueChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
    var item = d as AnimateBehavior;
    if (item == null || item.AssociatedObject == null) {
      return;
    }
    var newAnimation = new DoubleAnimation((double) e.NewValue, new Duration(new TimeSpan(0, 0, 1)));
    item.AssociatedObject.BeginAnimation(item.ToAnimate, newAnimation);
  }
}

现在在 xaml 中:

<TextBlock Text="Hello">
  <i:Interaction.Behaviors>
    <local:AnimateBehavior ToAnimate="{x:Static TextBlock.OpacityProperty}" Value="{Binding ValueYouWantToBindToOpacity}" />
  </i:Interaction.Behaviors>
</TextBlock>

现在使用这种方法,您可以为该控件的任何具有双精度类型值的 DP 设置动画。喜欢OpacityFontSize ...

这里与您的原始要求的主要区别是我们不将Value 绑定到元素。相反,我们将其绑定到Behavior。现在,当这种情况发生变化时,我们会在行为中检测到它,并通过行为的 AssociatedObject 属性,将动画应用于实际项目。

我们还通过提供属性在值通过 DP 更改为行为时进行动画处理来满足您满足多种双 DP 类型的要求。

如果您想要更通用,您可以使 Behavior 也接受持续时间和动画类型,使其更通用。

替代 DP 识别属性:

如果您绝对想传入“不透明度”而不是 DP,请尝试以下操作:

public static readonly DependencyProperty ToAnimateProperty =
  DependencyProperty.Register("ToAnimate", typeof(PropertyPath),
    typeof(AnimateBehavior), new FrameworkPropertyMetadata(null));

public PropertyPath ToAnimate
{
  get { return (PropertyPath)GetValue(ToAnimateProperty); }
  set { SetValue(ToAnimateProperty, value); }
}

所以我们将ToAnimate 设为PropertyPath

ValueChanged函数中

private static void ValueChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) {
  var item = d as AnimateBehavior;
  if (item == null || item.AssociatedObject == null) {
    return;
  }
  var sb = new Storyboard();
  var newAnimation = new DoubleAnimation((double) e.NewValue, new Duration(new TimeSpan(0, 0, 1)));
  Storyboard.SetTarget(newAnimation, item.AssociatedObject);
  Storyboard.SetTargetProperty(newAnimation, item.ToAnimate);
  sb.Children.Add(newAnimation);
  sb.Begin();
}

我们创建一个Storyboard 并使用PropertyPath,您可以拥有:

<TextBlock Text="Hello">
  <i:Interaction.Behaviors>
    <local:AnimateBehavior ToAnimate="Opacity" Value="{Binding ValueYouWantToBindToOpacity}" />
  </i:Interaction.Behaviors>
</TextBlock>

我仍然更喜欢 DP 而不是这种方法。

【讨论】:

  • 真是太好了!非常感谢!
  • 您的解决方案非常棒,真的。现在,我仍然有兴趣让它更短。如何仍然使用附加属性但要更改它以便将其编写如下:attached:AnimateProperty="{AnimatePropertyData Path=(UIElement.Opacity), Value={Binding OpacityValue}}" 然后以某种方式解决属性路径主人..?你知道我要去哪里吗?
  • 您的解决方案有两件事困扰着我:1. 绑定到静态 DependencyProperty 不是标准的(至少据我所知不是..) 2. 我希望将它与对象的定义,如在同一行内,就像附加属性语法一样。
  • 附加属性不适用于这些东西,它是您传递给它们的单个值或您无法在 xaml 中实例化的复杂类型。行为旨在通过其关联对象为您提供这种级别的控制。
  • "1. 绑定到静态 DependencyProperty 不是标准的(至少据我所知不是..)" 这是类型,它永远不会改变,绑定到强类型比键入字符串更好并在运行时反映它,没有类型安全。总是尽量选择强类型绑定,即使它是你自己的枚举
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多