11

Can anybody explain the difference and relationship between

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true)

and

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

They are required to reduce flickers, but when and how to use them correctly? Can they be used individually, or must be used in pairs, and what's the reason for that?

Thanks!

Credits:

The first code snippet was cited from MSDN page; the second code snippet was found on How to fix the flickering in User controls, the original author is @HansPassant.

Community
  • 1
  • 1
nevets
  • 4,631
  • 24
  • 40
  • first - ControlStyles.AllPaintingInWmPaint should be used with ControlStyles.UserPaint,having said that what setstyle with those options do is equivalent to this.DoubleBuffered = true;.Now the difference is setstyle is applied to the control level(ex:a form with controls this would apply only to the form),while CreateParams would apply to all controls in the form including the form. – terrybozzio Sep 16 '14 at 15:46
  • http://www.csharptutorial.in/15/csharp-how-to-avoid-flickering-in-csharp - From what I get from this link its about scope. – Caramiriel Sep 16 '14 at 19:55

1 Answers1

12

Thanks to @terrybozzlo for explanation and @Caramiriel for the great page that clarifies the problem.

I would like to summarize all I got here.


Why we got flickers

Flickers usually occur when your form, or a container control, such as a Panel, contains too many controls (and when WS_CLIPCHILDREN is turned on, which is the case by default). According to @HansPassant:

It draws the BackgroundImage, leaving holes where the child control windows go. Each child control then gets a message to paint itself, they'll fill in the hole with their window content. When you have a lot of controls, those holes are visible to the user for a while. They are normally white, contrasting badly with the BackgroundImage when it is dark. Or they can be black if the form has its Opacity or TransparencyKey property set, contrasting badly with just about anything.

How to avoid them on Control Level

You should set the Control's DoubleBuffered property to true. To do this, you need to derive the control (if it's not a user control) from the basic type and set it in the constructor.

For example, to get a Panel double buffered, you need to do:

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

Alternatively, you can use:

SetStyle(ControlStyles.UserPaint |
         ControlStyles.AllPaintingInWmPaint |
         ControlStyles.DoubleBuffer, true);

to obtain the identical effect, i.e. they are equivalent.

How to avoid them on Form Level

The above technique will reduce the flicker on control level, which means when the form get redrawn, all controls won't flicker any more. But the ultimate solution is to reduce flicker from the form level: when the form get redrawn, the form and all its children are double buffered.

This requires overriding CreateParams:

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

Summary

SetStyle does the job on control level, and CreateParam on Form level, and achieves double buffer to all control inside the form.

Credits:

@terrybozzlo, @Caramiriel, @HansPassant

Velcro
  • 546
  • 1
  • 8
  • 27
nevets
  • 4,631
  • 24
  • 40
  • *...leaving holes where the child control windows go*. No. This happens when you set WS_CLIPCHILDREN otherwise it draws into the entire area including the child controls. – γηράσκω δ' αεί πολλά διδασκόμε Sep 16 '14 at 21:02
  • SETSTYLE doesn't remove flicker and can't be use on a specific Control just to the entire form. CreateParams works at the beginning but when you resize you loose that property and controls start to flicker again. Do you know some solution to this? – Tanner Ornelas Nov 05 '18 at 21:31
  • As @TannerOrnelas said, when you resize the form the controls start to flicker again. Does anyone have a solution? I have tried a lot of things like the one in this post https://stackoverflow.com/questions/3286373/flickering-in-a-windows-forms-app but I cannot get a real solution. I would really appreciate any help. – Ignacio Mar 29 '19 at 18:06
  • 1
    @Ignacio As this answer states, you need to create your own class derived from Panel, or simply create a User Control. The Panel control does not have the option to DoubleBuffer as is, so using the `CreateParams` method will not work, because the panel won't inherit the DoubleBuffered property. In your derived class or UserControl constructor(s), add the following `SetStyle(ControlStyles.ResizeRedraw | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.SupportsTransparentBackColor, true);` Draw on this panel instead. – Smitty-Werben-Jager-Manjenson Mar 31 '20 at 19:38
  • Thank you! Creating a UserControl and using the `SetStyle` in the constructor worked for me. No more flicker when drawing shapes on my new UserControl. – Smitty-Werben-Jager-Manjenson Mar 31 '20 at 19:40