如何获取DependencyProperty动画的中间值/步骤?

时间:2014-02-12 10:41:53

标签: c# animation windows-store-apps dependency-properties

我正在开发Windows Store 8.1 App项目,并希望创建自定义进度条/仪表控件。该类在内部测量一些值并将其显示为文本和进度条/仪表。价值变化应该是动画的:

public class CustomGauge : UserControl{

    private static readonly DependencyProperty SpeedProperty = DependencyProperty.Register("Speed", typeof(double), typeof(CustomGauge), new PropertyMetadata(null, new PropertyChangedCallback(SpeedChanged)));
    private double Speed{
        get { return (double)GetValue(SpeedProperty ); }
        set { SetValue(SpeedProperty , value); }
    }

    // In CustomGauge.xaml a TextBlock uses a Binding to Speed to display the value


    private static void SpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        CustomGauge gauge = d as CustomGauge;
        if (gauge != null)
            gauge.DrawSpeed();
    }

    private void OnSpeedChanged(double newSpeedValue) {
        DoubleAnimation animation = new DoubleAnimation();
        animation.EnableDependentAnimation = true;
        animation.Duration = new Duration(TimeSpan.FromSeconds(1.5));
        animation.To = newSpeedValue;

        PowerEase easing = new PowerEase();
        easing.Power = 5.0;
        easing.EasingMode = EasingMode.EaseOut;

        animation.EasingFunction = easing;

        Storyboard storyboard = new Storyboard();
        storyboard.Children.Add(animation);
        Storyboard.SetTarget(animation, this);
        Storyboard.SetTargetProperty(animation, "Speed");

        storyboard.Begin();
    }

    private void DrawSpeed() {
        ...
    }
}

虽然使用绑定到“速度”的XAML文本块的文本是动画的,但是仪表/进度条只是从旧值跳转到没有动画的新值。这是因为SpeedChanged(...)仅使用新值调用一次,而不是从旧值到新值调用动画的每个中间值。

我该如何解决这个问题,并使用动画来改变仪表/进度条?

1 个答案:

答案 0 :(得分:0)

您可以做的一件事是为动画创建“步长”和“步时”。它将获取给定的值,找出差异,并将差异切割成块,为每个块制作动画。

注意:我使用WinRTXamlToolkit作为他们真棒StoryBoard Extensions。这可能是不必要的,如果你选择不整合整个库,很容易添加一个扩展。

// Set this to something sensible for your speeds.
// You may want to have it be calculated on the fly,
// Such as by doing an even distribution of steps,
// Possibly with a minimum value for a step to be. Up to you.
private const double StepSize = 5; 

private const double StepTime = 1.5;

private async void OnSpeedChanged(double newSpeedValue) {

    DoubleAnimation animation = new DoubleAnimation();
    animation.EnableDependentAnimation = true;

    PowerEase easing = new PowerEase();
    easing.Power = 5.0;
    easing.EasingMode = EasingMode.EaseOut;

    animation.EasingFunction = easing;

    Storyboard storyboard = new Storyboard();
    storyboard.Children.Add(animation);
    Storyboard.SetTarget(animation, this);
    Storyboard.SetTargetProperty(animation, "Speed");

    // You may want to have this be an absolute value and store the sign
    // in case there is both a positive and negative change in speed
    var difference = newSpeedValue - Speed;

    for(double stepValue = Speed + StepSize; i < difference; i += StepSize)
    {
        animation.Duration = new Duration(TimeSpan.FromSeconds(StepTime));
        animation.To = stepValue;

        await storyboard.BeginAsync();
    }

    // do the last one
    animation.Duration = new Duration(TimeSpan.FromSeconds(StepTime));
    animation.To = newSpeedValue;

    await storyboard.BeginAsync();
}

最后要注意的是我已经使OnSpeedChanged异步。对于SpeedChanged方法,它只是“设置并忘记它”,因为它会调用它并立即继续。如果你的速度经常变化,你需要做一些链接效果,比如用CancellationToken取消最后的动画。另一种选择是保持正在运行的动画任务的队列并按顺序运行它们。出于多种原因,这可能是也可能不是一个好主意。

希望这有助于编码!