关于 c#:表单级别是否有”Application.DoEvents”?

Is there an 'Application.DoEvents' at the form level?

我目前有一个应用程序可以生成单个 win 表单的多个实例。表单的每个实例都有一个计时器,它以大约 1 滴答/秒的速率更新许多控件和表单本身的一些属性。一旦应用程序达到一定数量的表单,它就会停止绘制在计时器滴答内发生的"更新"。

我想将 UI 线程保持在计时器的底部,并允许在不调用 Application.DoEvents 的情况下重新绘制表单(我的理解是 Application.DoEvents() 处理整个应用程序中的所有待处理窗口消息(可能包括其他timers \\'ticks\\'?-不确定)当我希望它处理的只是重新绘制表单时,因为许多控件已经更新)。


我不清楚你为什么要调用 DoEvents。为什么不让窗口适当地重新粉刷自己呢?它目前的行为方式有什么问题?

DoEvents 的调用通常表明某些事情应该在后台线程中 - 在您的情况下,这听起来实际上可能只是您有太多的事件正在发生。如果您的 GUI 太复杂以至于无法在一秒钟内重新绘制自己,那么听起来这可能是 UI 本身的设计问题。


如果您只想重绘表单或特定控件,只需在相关表单/控件上调用 Control.Refresh。

话虽如此,这通常(如 Application.DoEvents)表明重新设计是有序的。如果您有这样长时间运行的进程,最好将工作推送到 BackgroundWorker 中,这将使实际的计算工作在后台线程中运行,并防止 UI 变得无响应。


消息循环和对 Application.DoEvents() 的调用分派了三类 Windows 消息。首先是使用 SendMessage() 发送的消息。它们很重要,需要立即调度它们,因为还有其他程序在等待 SendMessage() 调用的结果。它们不放在消息队列中,Windows 直接调用窗口过程。

然后有消息通过 PostMessage() 放入消息队列中。他们可以等待,他们只是通知。所有键盘和鼠标消息都属于该类别。

然后是低优先级消息,WM_TIMER 和 WM_PAINT。它们只有在没有其他事情可做、没有 SendMessage 待处理且消息队列为空时才会被调度。

听起来你让自己陷入了这样一个境地,你让 Windows 严重挨饿,以至于它无法再发送那些低优先级的消息了。可能不再获得计时器 Ticks 或 Paint 事件。每秒只调用一次 DoEvents 肯定会做到这一点。这很糟糕,您的程序现在也影响其他程序的操作。你必须解决这个问题。通过重新架构您的应用程序来做到这一点,这样您就不再依赖 DoEvents。


我的 2c:

在每个表单中都有一个计时器会降低性能。每个窗口每隔一秒都会请求应用程序切换到该窗口的"上下文"并执行一些代码。整个开关可能比您的代码实际运行所需的时间更长。再加上您的所有表单都在同一个"上下文"中这一可能的事实。

如果可能,请考虑这样的事情:

1
2
3
4
5
6
7
8
List<MyForm> listofmyform;

Timer t = new Timer()
t.tick += delegate
{
    foreach(MyForm thisform in listofmyform)
        thisform.DoUpdate();
}

这只使用一个计时器来更新您的所有表单,只需要一个"上下文切换",并且可能会解决您遇到的一些性能问题。