wpf – 为什么这个旋转动画变得不稳定?

我有一个
WPF应用程序,图像保持旋转,偶尔会有一些动画.应用程序播放时,旋转保持平稳运行,但两个关键帧保持相同值的时间除外.出于演示目的,我将其简化为最基本的要点:

<Window x:Class="WpfApplication3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525"
    x:Name="RootElement">
<Window.Resources>

    <Storyboard x:Key="Storyboard1">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="image">
            <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
            <SplineDoubleKeyFrame KeyTime="0:0:1" Value="1"/>
            <SplineDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
            <SplineDoubleKeyFrame KeyTime="0:0:4" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>

</Window.Resources>
<Window.Triggers>
    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
        <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
    </EventTrigger>
</Window.Triggers>
<Grid>
    <Image x:Name="image" Source="image.jpg" RenderTransformOrigin="0.5,0.5" >
        <Image.RenderTransform>
            <RotateTransform Angle="{Binding Angle, ElementName=RootElement}" />
        </Image.RenderTransform>
    </Image>
</Grid>

该窗口包含一个图像元素,该图像元素具有RotateTransform作为其rendertransform,其旋转角度绑定到窗口代码隐藏中的属性.

还有一个动画会在第一秒内将图像的不透明度从0变为1,然后在接下来的两秒内将其保持为1,然后在最后一秒将其从1淡化为0.

代码隐藏看起来像这样:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public MainWindow()
    {
        InitializeComponent();

        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(1.0 / 30.0);
        timer.Tick += timer_Tick;
        timer.Start();
    }

    void timer_Tick(object sender, EventArgs e)
    {
        Angle += 360.0 * timer.Interval.TotalSeconds;
    }

    private DispatcherTimer timer;
    private double angle;

    public double Angle
    {
        get { return angle; }
        set 
        { 
            angle = value; 

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Angle"));
            }
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
}

有一个属性Angle类型double,包含RotateTransform的角度值.它使用INotifyPropertyChanged的事件处理程序来通知绑定的更改项.还有一个DispatcherTimer每秒触发30次,并且在每个刻度上它稍微增加了Angle属性,以便它保持旋转.

如果运行该应用程序,您会发现图像以每秒1转的速度以30fps的速度旋转.它在第一秒内平滑地旋转和淡入,但是在不透明度保持为1的两秒期间,旋转变得非常不稳定.然后,当不透明度开始渐渐变回0时,旋转再次平滑.

奇怪的是,如果您确定不透明度不会保持在1,则可以修复此问题:如果您在这两秒内稍微增加它:

<SplineDoubleKeyFrame KeyTime="0:0:3" Value="1.001"/>

……旋转保持平稳.

这里发生了什么?

最佳答案 DispatcherTimer的默认优先级是Background.该优先级描述如下:在完成所有其他非空闲操作之后处理操作.

DoubleAnimationUsingKeyFrames可能会优化掉重绘调用,因为不透明度没有改变,并且无论出于何种原因,这似乎会影响调度程序队列.

使用新的DispatcherTimer(DispatcherPriority.Normal)更改调度程序计时器优先级,或者实例化另一个DoubleAnimation以设置角度动画,而不是手动设置动画.

点赞