4

我有一个 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 作为其渲染变换,旋转的角度绑定到窗口代码隐藏中的一个属性。

还有一个动画在第一秒内将图像的不透明度从 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;
}

有一个 double 类型的属性 Angle,它包含 RotateTransform 的角度值。它使用 INotifyPropertyChanged 的​​事件处理程序来通知绑定项的更改。还有一个每秒触发 30 次的 DispatcherTimer,并且在每个滴答声中,它都会略微增加 Angle 属性以使其保持旋转。

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

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

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

...旋转保持平稳。

这里发生了什么?

4

1 回答 1

2

的默认优先级DispatcherTimerBackground。此优先级描述如下:在所有其他非空闲操作完成后处理操作。

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

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

于 2014-07-28T12:12:42.217 回答