【问题标题】:How to get the intermediate values/steps of an animation of an DependencyProperty?如何获取 DependencyProperty 动画的中间值/步骤?
【发布时间】:2014-03-10 15:18:23
【问题描述】:

我正在开发 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 TextBlock 的文本动画时,仪表/进度条只是从旧值跳转到新值而没有动画。这是因为 SpeedChanged(...) 只使用新值调用一次,而不是从旧值到新值的动画的每个中间值。

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

【问题讨论】:

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


    【解决方案1】:

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

    注意:我使用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 取消最后的动画。另一种选择是保留正在运行的动画任务的队列并按顺序运行它们。出于多种原因,这可能是一个好主意,也可能不是一个好主意。

    希望这对编码有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-24
      • 2017-04-05
      • 2015-04-09
      • 1970-01-01
      • 2012-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多