Control.Invalidate, Control.Update 和 Control.Refresh之间的区别是什么?
在讨论上述各功能之前,让我们看一下winforms 控件是如何进行绘制的。
Windows控件绘制是对WM_PAINT消息的响应,此消息在调用UpdateWindow和RedrawWindow时发送,或者当应用程序通过消息队列获得WM_PAINT时,通过DispatchMessage函数发送此消息。在获得WM_PAINT消息时,控件绘制它的背景,然后在必要时绘制它的前景。绘画时执行双缓冲和透明原则,然后触发OnPaint事件,让用户有机会执行自定义绘画。
在此背景下,让我们更详细地了解一下上面提到的三个函数。
Control.Invalidate( ) / Control.Invalidate(bool) / Control.Invalidate(Rectangle) / Control.Invalidate(Rectangle, bool) / Control.Invalidate(Region) / Control.Invalidate(Region, bool)
bool参数表示用户是否想要使其正在调用Invalidate函数控件的子控件无效。Rectangle参数是要失效的边界,region参数是要失效的区域。所有重载本质上都会最终调用RedrawWindow、InvalidateRect或invalidateRgn函数之中的一个。如果调用RedrawWindow,则可能会导致WM_PAINT消息被发送至应用程序的消息队列(使子控件无效)。这里需要注意的重要一点是,这些函数仅会通过将客户区域添加至控件窗口的当前更新区域来使客户区域“无效‘或”dirty“。当收到下一条WM_PAINT消息时,该无效区域以及更新区域中的所有其它区域均被标记为正在绘制。结果就是,你可能不会立即(或同步)看到控件刷新(并显示无效)。
Control.Update()
Update函数调用UpdateWindow函数,如果窗口的更新区域不为空,该函数会通过向窗口(控件的窗口)发送WM_PAINT消息来更新控件的客户区域。此函数绕过应用程序的消息队列,直接向WNDPROC()发送WM_PAINT消息。因此,如果窗口更新区域之前已经”失效“了,则调用”update“函数会立即”更新“(并导致重新绘制)失效区域。
Control.Refresh()
到现在,你可能已经猜到Refresh()函数是用来做什么了。是的,它会调用Invalidate(true)使控件失效及其子控件失效,然后调用Update()强制绘制控件,所以说失效是同步进行的。