为什么在Windows 10中的后台线程中运行控件时,无法在WPF应用程序中获得平滑的60 FPS动画?

Mar*_*las 5 c# wpf animation multithreading

我正在尝试在后台线程中托管一个控件,这样即使UI线程被阻止,它也可以以60 FPS的恒定速度显示动画.这在Windows 8.1中完美运行,但自从升级到Windows 10后,它现在失败了.

我从托管控件的后台线程挂钩CompositionTarget.Rendering事件,以便动画可以与监视器刷新同步.但似乎只要主UI线程中的某些内容也挂钩到Rendering事件,只要主UI线程中托管的可视化更改,就会跳过框架.

我可以在视觉上看到跳过的帧,并且根据RenderingEventArgs类中公开的RenderTime,这确认正在跳过帧,因为每当帧跳过发生时,自上一帧以来的时间增量大约为33ms而不是16ms.

可以通过在UI线程中挂钩CompositionTarget.Rendering事件并在事件处理程序中执行任何操作,或者通过启动故事板动画来引发跳过,我猜测是因为故事板动画挂钩了CompositionTarget.Rendering事件以实现平滑动画.

这是一个简单的示例项目,它演示了这个问题:

SmoothAnimationTest.zip

我已经在Windows 8.1和Windows 10上在几台机器上进行了测试,在任何情况下,无论如何,Windows 8.1都能以60 FPS的"自有线程"控制完美运行.在Windows 10中,"显示抖动1"将帧速率降低到恒定的30 FPS,"显示抖动2"导致帧速率在30到60 FPS之间不规律地切换,平均大约45-50.

在Windows 8.1和Windows 10中,按下"阻止UI线程"按钮可在单独的线程控制中获得平滑的60 FPS.

一个解决方案是让动画在UI线程中运行并从该线程中删除所有阻塞代码,不幸的是,这不是一个简单的任务,因为我正在处理的应用程序很复杂,并且UI可以阻止很多地方超过几毫秒,这可能会导致动画中的抖动.

Mar*_*rko 0

这可能不是完整的答案,但我认为最好不要将其写为评论。

首先,您是否已确认问题不在于 .Net 4.6?Win 10 附带 .Net 4.6,它取代了 Win 8.1 附带的 .Net 4.5。.Net 4.6 包含相当多的内部更改和新错误。我将在 Win 8.1 上安装 .Net 4.6 以验证这一点,这是我的第一步...(如果错误与 .Net 4.6 相关,那么您必须通过Connect报告它,但不要抱太大希望。这可能需要数年时间以便修复该错误(如果有的话)

其次,我不太清楚你如何显示你的控制权,但听起来你需要第二个调度程序。但这将需要另一个窗口。这样,主窗口上发生的任何事情都不会影响辅助窗口。

就像我说的,我不知道这个选项在你的场景中是否可行。也许使第二个窗口无边框,位于最上面并与第一个窗口重叠......