通过双缓冲区减少闪烁:SetStyle与重写CreateParam

时间:2014-09-16 15:31:20

标签: c# winforms flicker

任何人都可以解释

之间的区别和关系
SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true)

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
}

他们需要减少闪烁,但是何时以及如何正确使用它们?它们可以单独使用,还是必须成对使用,这是什么原因?

谢谢!

积分

第一个代码段引自MSDN page;第二个代码段在How to fix the flickering in User controls上找到,原作者是@HansPassant。

1 个答案:

答案 0 :(得分:9)

感谢@terrybozzlo的解释,感谢@Caramiriel这个澄清问题的精彩页面。

我想总结一下我来到这里的所有内容。


为什么我们会出现闪烁

当您的表单或容器控件(例如Panel)包含太多控件(以及启用WS_CLIPCHILDREN时默认情况下)时,通常会出现闪烁现象。根据@HansPassant:

  

它绘制了BackgroundImage,在子控件窗口的位置留下了空洞。然后每个子控件都会收到一条消息来绘制自己,他们将用他们的窗口内容填充这个洞。当您有很多控件时,用户可以看到这些漏洞一段时间。它们通常是白色的,在黑暗时与BackgroundImage形成鲜明对比。或者如果表单设置了Opacity或TransparencyKey属性,它们可能是黑色的,与几乎任何东西形成鲜明对比。

如何在控制级别上避免它们

您应该将Control的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