有这种情况 - 我在C#(WPF)上制作了一些数学建模应用程序,显示它是实时矢量图形的结果。数学做得很好(迭代过程,每帧绘图),但有问题 - 虽然我使用额外的线程进行计算,绘制结果应该使用Dispatcher.BeginInvoke(每帧!),这是一个相当昂贵的操作(分析显示它花了将近30%的时间)。 但是如果我尝试在UI线程中完成所有操作,我只会看到最后一帧(如预期的那样)。
计算并显示结果是应用程序的唯一任务,因此我甚至不需要GUI来进行建模时的响应 - 但我需要实时显示结果......
所以我想避免使用BeginInvoke并同时显示结果,我看不到任何方法。有任何想法如何以这种方式安排计算? 图形在DrawingVisual中显示在一些空的FrameworkElement中。
THX
答案 0 :(得分:1)
选项1:渲染事件
在单独的线程上进行计算,但是队列更改到UI并在Rendering事件上更新它们。它看起来像这样:
PresentationSource.FromVisual(window).CompositionTarget.Rendering += (obj, e) =>
{
foreach(var update in _queue)
UpdateUI(update);
}
此代码假定_queue是一个线程安全(同步)队列。您可以创建这样的队列类或下载一个。或者,您可以使用“lock(_queue)”包围“foreach”。
这比Dispatcher.BeginInvoke()更好的原因是:1。它在每个帧之前调用,因此如果帧速率下降则调用频率较低,并且2.它会批量处理更改。
选项2:多个UI线程
您可以使用单独的hWnd在单独的线程上运行部分UI。您可以使用WindowsFormsIntegration或使用一些Win32魔术。这是一种方法:
((HwndSource)PresentationSource.FromVisual(window)).Handle
选项3:动画
您可以创建自己的自定义动画派生类来为UI项目设置动画。这些可以使用从模型中预先调整的数据。这样做的好处是精确的时间同步:每次调用代码时,它都准确地知道“何时”(在动画时间内)它正在计算位置。因此,如果某个其他程序占用CPU或GPU一秒钟并且速度减慢和帧速率,动画仍然会以较低的帧速率平稳地进行。
为此,子类DoubleAnimationBase
并重写GetCurrentValueCore()以进行自定义计算,并结合所需的Clone()和CreateInstanceCore()覆盖。然后使用它来为您的属性设置动画。
如果仅仅为现有对象的Double属性设置动画是不够的,则可以创建一个动画来生成整个对象,例如Geometry,Geometry3D,Drawing,Drawing3D甚至UIElement。为此,子类化AnimationTimeline并覆盖GetCurrentValue()和其他。
使用动画的优势与渲染事件相同,除了您可以让WPF处理所有时钟同步并重播速度问题,而不是自己动手。如果只能为正在变化的属性设置动画,它也可能导致代码减少。
答案 1 :(得分:0)
在每个迭代过程结束时,您可以手动调用需要重绘的可视对象上的InvalidateVisual()方法,这将发送绘制消息以重绘控件/窗口。
答案 2 :(得分:0)
使用DataBinding,让我们通过ObservableCollection来考虑刷新你的UI。 祝你好运