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

nev*_*ets 9 c# flicker winforms

任何人都可以解释它们之间的区别和关系

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true)
Run Code Online (Sandbox Code Playgroud)

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

谢谢!

积分:

第一个代码片段是从MSDN页面引用的; 在如何修复用户控件中的闪烁中找到第二个代码片段,原始作者是@HansPassant.

nev*_*ets 9

感谢@terrybozzlo的解释和@Caramiriel这个澄清问题的好页面.

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


为什么我们得到了闪烁

当您的表单或容器控件(如a Panel)包含太多控件(以及何时WS_CLIPCHILDREN打开,默认情况下是这种情况)时,通常会出现闪烁.据@HansPassant说:

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

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

您应该将Control的DoubleBuffered属性设置为true.为此,您需要从基本类型派生控件(如果它不是用户控件)并在构造函数中设置它.

例如,要获得Panel双缓冲,您需要执行以下操作:

public class BufferedPanel : Panel
{
    public BufferedPanel()
    {
        DoubleBuffered = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用:

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true);
Run Code Online (Sandbox Code Playgroud)

获得相同的效果,即它们是等价的.

如何在表单级别上避免它们

上述技术将减少控制级别的闪烁,这意味着当重新绘制表单时,所有控件都不会再闪烁.但最终的解决方案是减少表单级别的闪烁:当表单重新绘制时,表单及其所有子项都是双缓冲的.

这需要覆盖CreateParams:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
        return cp;
    }
}
Run Code Online (Sandbox Code Playgroud)

摘要

SetStyle在控件级别和CreateParam表单级别上完成工作,并为表单内的所有控件实现双缓冲.

积分:

@terrybozzlo,@ Caramiriel,@ HansPassant