【发布时间】:2013-01-16 09:02:45
【问题描述】:
在我的 WPF 应用程序中,用户按下按钮以启动 3D 模型平滑旋转,然后松开按钮以停止旋转。
为此,我创建了一个 DispatcherTimer:
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += new EventHandler( timer_Tick );
timer.Interval = new TimeSpan( 0, 0, 0, 0, 30 );
当按下按钮时我调用timer.Start(),当松开按钮时我调用timer.Stop()。
timer_Tick 函数改变模型的旋转:
void timer_Tick( object sender, EventArgs e )
{
spin = ( spin + 2 ) % 360;
AxisAngleRotation3D rotation = new AxisAngleRotation3D( new Vector3D( 0, 1, 0 ), spin );
Transform3D rotate = new RotateTransform3D( rotation );
model2.Transform = rotate;
}
我注意到,模型大部分时间都在平稳旋转,但经常冻结和卡顿,停顿的时间不同,有时长达 1/4 秒。
有没有办法让它更流畅?我知道通过使用 DispatcherTimer(而不是 System.Timers.Timer),回调发生在 UI 线程上。但我必须在 UI 威胁下才能运行线路
model2.Transform = rotate;
我已经阅读了有关在其他线程上获取计时器回调的各种方法。但似乎最终我必须与 UI 线程同步才能调用该行。如果我使用 Invoke() 将 System.Timers.Timer 回调线程编组到 UI 线程,这会带来整体更流畅的动画吗?似乎不应该,因为它必须与 UI 线程同步,就像 DispatcherTimer 可能所做的那样。就此而言,对于 UI 线程而言,似乎 任何 定期设置 model2.Transform 的方案都在同一条船上,不是吗?
(作为一个可能是次要的问题,我首先试图了解导致暂停的原因。据我所知,UI 线程正在做的其他事情没有什么重要的。所以我不明白是什么在这些暂停期间发生。垃圾收集?看起来不应该收集太多垃圾,而且暂停似乎不会那么极端。)
【问题讨论】:
-
我认为您可以使用 model2.Dispatcher.BeginInvoke(new Action(() => { model2.Transform = rotate; })) 在 model2 父线程中调用它
-
您似乎知道,通过使用替代计时器,您需要分派回 UI 线程,那么为什么要问这样做是否会产生更好的结果呢?你试过了吗?
-
你想旋转什么样的物体?有可能是一些视觉元素,例如阴影或不透明蒙版,导致渲染性能不佳...
-
@acrilige 和 Daniel Kelly:我使用上面显示的 BeginInvoke() 行 acrilige 和常规计时器,它实际上提供了平滑的旋转。 Henk 在下面的回答对我仍然有用,因为它有助于表明 DispatchTimer 本身的优先级,而不是与 UI 线程本身同步,导致了卡顿。
-
我知道它已经很老了,但如果有人偶然发现这个问题 - 我建议改用 Storyboard。我们在这里看到的不是 WPF 进行渲染转换的方式。我想知道它是如何工作的。
标签: c# wpf timer smooth dispatchertimer