【问题标题】:Is there a clean way to animate the value of a readonly DependencyProperty?有没有一种干净的方法来为只读 DependencyProperty 的值设置动画?
【发布时间】:2015-04-28 17:25:32
【问题描述】:

我有一个控件,我想为只读DependencyProperty 的值设置动画

像这样使用原版动画不起作用(如预期的那样):

var animation = new DoubleAnimation(value, TimeSpan.FromMilliseconds(100));
this.BeginAnimation(SomeValueProperty, animation);

我想我正在寻找类似的东西:

var animation = new DoubleAnimation(value, TimeSpan.FromMilliseconds(100));
this.BeginAnimation(SomeValuePropertyKey, animation);

有没有一种简洁的方法可以使用框架为我的属性设置动画?

【问题讨论】:

  • 即使您将 SomeValueProperty.DependencyProperty 传递给 BeginAnimation,它也会给您一个运行时异常,因为 DependencyProperty.RegisterReadOnly 会在属性元数据上设置 IsAnimationProhibited = true
  • 是的,如果可以从外部更改只读 dp 的 dp 是没有意义的。采用 DependencyPropertyKey 的 BeginAnimation 的重载会很好。我的想法用完了,所以我问了这个问题。不想滚动我自己的动画。

标签: wpf animation wpf-controls dependency-properties


【解决方案1】:

找到了一个~聪明~的解决方案:

public class DummyControl : Control
{
    internal static readonly DependencyPropertyKey SomePropPropertyKey = DependencyProperty.RegisterReadOnly(
        "SomeProp",
        typeof(double),
        typeof(DummyControl),
        new PropertyMetadata(0.0));

    // A proxy that is used for animating. Sets the value of the readonly property on change.
    private static readonly DependencyProperty SomePropProxyProperty = DependencyProperty.Register(
        "SomePropProxy",
        typeof(double),
        typeof(DummyControl),
        new PropertyMetadata(0.0, OnSomePropProxyChanged));

    public static readonly DependencyProperty SomePropProperty = SomePropPropertyKey.DependencyProperty;

    public double SomeProp
    {
        get { return (double)this.GetValue(SomePropProperty); }
        protected set { this.SetValue(SomePropPropertyKey, value); }
    }

    public void AnimateTo(double value)
    {
        var animation = new DoubleAnimation(value, TimeSpan.FromMilliseconds(100));
        this.BeginAnimation(SomePropProxyProperty, animation);
        // We are animating the proxy here.
    }

    private static void OnSomePropProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        d.SetValue(SomePropPropertyKey, e.NewValue);
        // Updating the value of the readonly property here.
    }
}

这感觉不是一个非常干净的解决方案,但它至少使用标准动画。请提出更好的建议!

【讨论】:

  • 不幸的是,通过公开一种在控件之外设置该属性的明确方法,您打破了只读属性的目的。
【解决方案2】:

公开代理属性是一种解决方案,但缺点是这会使只读限制无效。一个稍微好一点的方法是创建一个代理对象。这将使动画属性只能在您正在编写的控件内访问。

public class AnimationProxy<T> : Animatable
{

    private Action<T> _valueUpdateCallback;

    #region AnimatableProperty

    public static readonly DependencyProperty AnimatablePropertyProperty =
        DependencyProperty.Register("AnimatableProperty", typeof(T), typeof(AnimationProxy<T>),
            new FrameworkPropertyMetadata(default(T),
                new PropertyChangedCallback(OnAnimatablePropertyChanged)));

    public T AnimatableProperty
    {
        get { return (T)GetValue(AnimatablePropertyProperty); }
        set { SetValue(AnimatablePropertyProperty, value); }
    }

    private static void OnAnimatablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        AnimationProxy<T> target = (AnimationProxy<T>)d;
        T oldAnimatableProperty = (T)e.OldValue;
        T newAnimatableProperty = target.AnimatableProperty;
        target.OnAnimatablePropertyChanged(oldAnimatableProperty, newAnimatableProperty);
    }

    protected virtual void OnAnimatablePropertyChanged(T oldAnimatableProperty, T newAnimatableProperty)
    {
        _valueUpdateCallback?.Invoke(newAnimatableProperty);
    }

    #endregion


    public AnimationProxy(Action<T> valueUpdateCallback)
    {
        _valueUpdateCallback = valueUpdateCallback;
    }

    //Override to keep compiler happy
    protected override Freezable CreateInstanceCore()
    {
        throw new NotImplementedException();
    }
}

所以现在要为只读属性设置动画,您只需提供回调并为代理对象设置动画:

var animationProxy = new AnimationProxy<double>(SetReadOnlyProperty);
animationProxy.AnimatableProperty = ReadOnlyProperty;
var animation = new DoubleAnimation(0, new Duration(CurrentTimeLeft));
animationProxy.BeginAnimation(AnimationProxy<double>.AnimatablePropertyProperty, animation);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    • 2011-06-12
    • 2012-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多