调用Invalidate
方法不会立即引发Paint
事件。它仅将指定区域设置为无效并将绘制事件排队。下一次调用Invalidate
仅将区域添加到先前无效的区域。只有当队列Paint
中没有事件时,它才会放置一个新事件。Paint
从方法的备注部分Invalidate
:
调用 Invalidate 方法不会强制同步绘制;要强制同步绘制,请Update
在调用 Invalidate 方法后调用该方法。不带参数调用此方法时,会将整个客户区添加到更新区域。
更多解释:
Windows Forms 技术是Win32
'suser32
库的包装器。要了解绘制事件的底层原理,您需要了解 user32 的工作原理。
Windows 中的每个进程都有一个消息队列。当属于进程的窗口发生任何事情时,Windows 会将事件推送到进程的消息队列中。每个应用程序中都有一个消息循环,它从队列中提取消息(通过调用)并分派消息(通过调用DispatchMessage()GetMessage()
调用适当的函数,称为 a )。所以消息一个接一个地被处理。这意味着当正在处理一条消息时,无法处理其他消息。
这就是为什么当您在表单中执行耗时的操作(没有启动新线程)时,应用程序停止响应:您卡在处理一条消息(例如Window Procedure
Click
按钮事件),因此应用程序无法处理其他消息(鼠标事件、绘画事件等)。
在 Windows 窗体中,Application.Run
方法运行应用程序的消息循环。消息传递给Control.WndProc方法,该方法确定OnXxxx
要调用的适当方法(OnKeyPress
、OnMouseMove
、OnResize
等),并且该方法引发相应的事件(KeyPress
、MouseMove
、Rezie
等)。
当需要绘制程序的窗口时(例如,当它首次显示或从最小化状态恢复时),WindowsWM_PAINT
将消息排队到消息队列中,前提是消息队列中没有未处理WM_PAINT
的窗口。此外,消息循环仅WM_PAINT
在队列中没有其他消息时才从队列中提取消息。来自WM_PAINT
MSDN 页面的引用:
当应用程序的消息队列中没有其他消息时,GetMessage 返回 WM_PAINT 消息,并且 DispatchMessage 将消息发送到相应的窗口过程。
在 Windows 窗体中,WM_PAINT
转换为OnPaint
引发Paint
事件的方法。
当您在一个方法中多次调用Invalidate
(调用 Win32函数)时,事件仍然没有机会被引发。当前正在处理的事件必须完成,同时发送的其他消息也应该被处理,然后引发事件。InvalidateRect
Paint
Paint
请按照答案中的链接仔细阅读。