2

每次更新 double 类型的属性时,我都试图找到一种运行动画的通用方法。

这必须是适用于所有双值的单一解决方案。这意味着我不想AttachedProperty为每个UIElement属性(一个用于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 一样。

4

1 回答 1

5

我的问题:

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

它必须是附属财产吗?您可以使用行为吗?

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

也许有一些黑客(我不知道)。再次,这是必须拦截和取消正常 DP 动作的绝对必要条件吗?

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

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

因此,如果您的要求是在绑定到值更改时为任何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 而不是这种方法。

于 2014-05-07T13:55:39.897 回答