防止.NET中的GUI更新事件泛滥

时间:2010-03-10 21:59:17

标签: .net events invoke

我正在创建一个系统,该系统从通过串行端口发送数据的硬件设备获取读数。每次“数据包”从串口进入时,我都会更新并重新绘制一些GUI组件以反映更新的信息。由于串口事件来自一个单独的线程,我必须在几个组件上调用Invoke(Invalidate)来重绘它们,这可能会导致GUI落后于串口数据,因为GUI会排队一堆如果硬件设备每秒开始发送500个数据包,则调用()请求。

有没有办法找出GUI组件上是否已经有一个Invoke(Invalidate)请求我可以阻止代码排队这些,或者我应该采取不同的方法来更新我的GUI组件?

5 个答案:

答案 0 :(得分:2)

我见过的最佳选择是使用新的Rx Framework

通过使用Rx框架,您可以将串行端口事件转换为IObservable<T>。如果你这样做,IObservable<T>提供了一个Throttle扩展方法,它允许你“扼制”嘈杂的事件流,使它们更容易管理。

答案 1 :(得分:1)

我的头脑中几个选项:

1)使用实例变量作为标志:_updatePending在调用之前设置为True,在调用调用时设置为false。如果flag为True,请不要调用Invoke(Invalidate)。

2)改为使用轮询机制:每隔X ms从后台线程更新的数据源更新GUI。

答案 2 :(得分:1)

请记住,您正在更新适合人眼的内容。一旦这些更新发生的速度超过每秒25次,我们就看不到任何东西。因此,缓冲从SerialPort获取的数据并且不要开始/调用(),直到自上次调用它以来最后50毫秒为止。

DateTime.UtcNow或Environment.TickCount允许您以(仅)足够的准确度计时。您可以毫不费力地避免以此速率停止UI线程。

答案 3 :(得分:1)

首先测试和测量。 Invalidate()是一个非常(非常)便宜的功能。只要您不强制任何绘画(更新,刷新),您就不会遇到性能问题。

你的第一个担心(可能,现在我猜是)应该是Invokes的数量,对MessagePump征税。也许你的接收逻辑可以节省一点。

回到原来的问题,存在一个Control.Invalidated属性,但我希望从另一个线程调用是不安全的。这会破坏目的。

答案 4 :(得分:0)

我倾向于将您需要的所有信息放在threadasafe Queue容器中,并在GUI中使用某种消息泵(最简单的是一个Timer)来读取该队列中的所有项目。