感谢@terrybozzlo的解释和@Caramiriel提供的清晰解析该问题的网页。
以下是我总结的所有内容:
我们为什么会遇到闪烁问题
当你的表单或一个容器控件(例如Panel
)包含太多控件时(并且默认情况下打开了WS_CLIPCHILDREN
),通常会出现闪烁问题。根据@HansPassant所说:
它绘制BackgroundImage,留下子控件窗口出现的空洞。然后每个子控件都会收到一条自己绘制的消息,他们将使用其窗口内容填充空洞。当你有很多控件时,这些空洞在一段时间内对用户可见。它们通常是白色的,在暗色背景图像上对比度非常差。或者如果表单具有其Opacity或TransparencyKey属性设置,则它们可以是黑色的,与任何东西都对比度非常差。
如何在控件级别上避免闪烁问题
您应该将控件的DoubleBuffered
属性设置为true
。为此,您需要从基本类型派生控件(如果它不是用户控件),并在构造函数中设置它。
例如,要使Panel
双缓冲,您需要执行以下操作:
public class BufferedPanel : Panel
{
public BufferedPanel()
{
DoubleBuffered = true;
}
}
作为替代方案,您可以使用:
SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.DoubleBuffer, true)
为了获得相同的效果,即它们是等价的。
如何在表单级别上避免它们
上述技术将减少控件级别上的闪烁,这意味着当表单重新绘制时,所有控件不再闪烁。但是最终的解决方案是从表单级别减少闪烁:当表单重新绘制时,表单及其所有子元素都是双缓冲的。
这需要重写CreateParams
:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
概要
SetStyle
在控件级别上完成任务,CreateParam
在表单级别上完成任务,并且实现了对表单内所有控件的双缓冲。
鸣谢:
@terrybozzlo, @Caramiriel, @HansPassant