Question

How can I set the protected DoubleBuffered property of the controls on a form that are suffering from flicker?

Was it helpful?

Solution

Here's a more generic version of Dummy's solution.

We can use reflection to get at the protected DoubleBuffered property, and then it can be set to true.

Note: You should pay your developer taxes and not use double-buffering if the user is running in a terminal services session (e.g. Remote Desktop) This helper method will not turn on double buffering if the person is running in remote desktop.

public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
   //Taxes: Remote Desktop Connection and painting
   //http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
   if (System.Windows.Forms.SystemInformation.TerminalServerSession)
      return;

   System.Reflection.PropertyInfo aProp = 
         typeof(System.Windows.Forms.Control).GetProperty(
               "DoubleBuffered", 
               System.Reflection.BindingFlags.NonPublic | 
               System.Reflection.BindingFlags.Instance);

   aProp.SetValue(c, true, null); 
}

OTHER TIPS

Check this thread

Repeating the core of that answer, you can turn on the WS_EX_COMPOSITED style flag on the window to get both the form and all of its controls double-buffered. The style flag is available since XP. It doesn't make painting faster but the entire window is drawn in an off-screen buffer and blitted to the screen in one whack. Making it look instant to the user's eyes without visible painting artifacts. It is not entirely trouble-free, some visual styles renderers can glitch on it, particularly TabControl when its has too many tabs. YMMV.

Paste this code into your form class:

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

The big difference between this technique and Winform's double-buffering support is that Winform's version only works on one control at at time. You will still see each individual control paint itself. Which can look like a flicker effect as well, particularly if the unpainted control rectangle contrasts badly with the window's background.

System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control)
    .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
    System.Reflection.BindingFlags.Instance);
aProp.SetValue(ListView1, true, null);

Ian has some more information about using this on a terminal server.

public void EnableDoubleBuffering()
{
   this.SetStyle(ControlStyles.DoubleBuffer | 
      ControlStyles.UserPaint | 
      ControlStyles.AllPaintingInWmPaint,
      true);
   this.UpdateStyles();
}

One way is to extend the specific control you want to double buffer and set the DoubleBuffered property inside the control's ctor.

For instance:

class Foo : Panel
{
    public Foo() { DoubleBuffered = true; }
}

nobugz gets the credit for the method in his link, I'm just reposting. Add this override to the Form:

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

This worked best for me, on Windows 7 I was getting large black blocks appearing when I resize a control heavy form. The control now bounce instead! But it's better.

Extension method to turn double buffering on or off for controls

public static class ControlExtentions
{
    /// <summary>
    /// Turn on or off control double buffering (Dirty hack!)
    /// </summary>
    /// <param name="control">Control to operate</param>
    /// <param name="setting">true to turn on double buffering</param>
    public static void MakeDoubleBuffered(this Control control, bool setting)
    {
        Type controlType = control.GetType();
        PropertyInfo pi = controlType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
        pi.SetValue(control, setting, null);
    }
}

Usage (for example how to make DataGridView DoubleBuffered):

DataGridView _grid = new DataGridView();
//  ...
_grid.MakeDoubleBuffered(true);

Before you try double buffering, see if SuspendLayout()/ResumeLayout() solve your problem.

This caused me a lot of grief for two days with a third party control until I tracked it down.

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

I recently had a lot of holes (droppings) when re-sizing / redrawing a control containing several other controls.

I tried WS_EX_COMPOSITED and WM_SETREDRAW but nothing worked until I used this:

private void myPanel_SizeChanged(object sender, EventArgs e)
{
     Application.DoEvents();
}

Just wanted to pass it on.

vb.net version of this fine solution....:

Protected Overrides ReadOnly Property CreateParams() As CreateParams
    Get
        Dim cp As CreateParams = MyBase.CreateParams
        cp.ExStyle = cp.ExStyle Or &H2000000
        Return cp
    End Get
End Property

You can also inherit the controls into your own classes, and set the property in there. This method is also nice if you tend to be doing a lot of set up that is the same on all of the controls.

I have found that simply setting the DoubleBuffered setting on the form automatically sets all the properties listed here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top