Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Flickering is a common problem known to everyone who has programmed in the Windows Forms environment. We all know that even the Windows Task Manager flickers when we select a process from the process list.

If you have ever looked around the subject you might have probably noticed that the most common solution to this is Double Buffering.

Explanation

Double Buffer is a technique where we draw all our graphic needs to an image stored in the memory (buffer) and after we are done with all our drawing needs we a draw a complete image from the memory onto the screen. This concentrates the drawing to the screen (an operation that badly effects the performance of the application) to a single operation rather than many small ones.

An easy example to understand this would be to use a ProgressBar that has several layers:

  1. background layer,
  2. border layer,
  3. progress layer,
  4. percent layer.

For each of these layers, we need to call some drawing operation, and after each drawing operation the control redraws itself to the screen. Now, if the refresh rate is low we won't have any problem but if we speed up the refresh rate flickering (blinking) occurs.

We solve this by drawing all the layers to an image that is located in the memory and after drawing all the layers into this image we draw the image onto the screen. This improves the performance dramatically.

Techniques

Note: All of the techniques that are mentioned below are used in the example source code provided with this article except the first one which is from .NET Framework 1.1, and the source code is for .NET Framework 2.0.

Things you should know before we start

Starting off

Conclusion

Double buffering is a good and simple to use technique that I think anyone who has ever dealt with some graphics programming should know. I am also glad to see that Microsoft has put up lot of time to improve the GUI performance of the .NET Framework and provided us with some better tools to deal with them instead of wasting our time on writing some improvised code.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralYES
bar49_9#
7:39 18 Jan '10  
I was getting ready to write a graphics test app but you wrote it for me.
Thank you!
GeneralGetting parameter Not valid error
prashant_144
3:03 19 Nov '09  
I am creating a User Control.
I set DoubleBuffering = true from design time.
When i run my application and try to load an image then it shows me the
error saying "Parameter Not valid" on line Application.Run(new Form1());

When i set it to false everything is ok.
I also tried your method by writing this line on constructor but same error occurred.

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

Help Needed
thanks,

adad

GeneralProblem in GDI+ drawing
skvs
22:42 3 Dec '08  
hi..
I have used the SetStype property that what u have used for BuiltInOptimisedBuffer, but still i have flickering problem..

If i open any other window in front of the painted area, it will again repaints the whole area, is there any way to not to effect the painted area, so that we can avoid repainting of that particular region..
GeneralRe: Problem in GDI+ drawing
Member 6284660
23:54 9 Aug '09  
Hi,

After putting this code in my control, it was still flickering, and I found the solution on another site : there's another parameter to pass to SetStyle (ControlStyles.DoubleBuffer).

Replace the SetStyle line by :
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);

And after that it will work!

Thanks for this great article man
QuestionHow do you double buffer the rendering of all form controls? Not just a single control?
johnnynine2
19:00 27 Jul '08  
This is a great article on how to double buffer a single control, so that the rendering of the control does not flicker.

However I need to double buffer the entire control collection rendering. I use my own transparent image controls on my form which don't paint a background. These images change frequently so the entire control collection needs to be redrawn often. This causes severe flicker as each control is redrawn in the form.

How do I double buffer the rendering of all the form controls so that I don't actually see each control being rendered in turn? I basically need each control to be rendered to an in memory graphics buffer, and then when done, render the graphics buffer.

Thanks,
Johnny
QuestionRe: How do you double buffer the rendering of all form controls? Not just a single control?
selin1005
22:45 2 Sep '08  
Did you get an answer for this or find a solution yourself? Because I'm stuck with the same problem. I have created separate event handlers for the same control so any mouse movement will update all the controls, and their draw methods work fine with flicker actually, but when I try to introduce buffering to remove flicker, I lose them completely!
AnswerRe: How do you double buffer the rendering of all form controls? Not just a single control?
selin1005
23:26 3 Sep '08  
Question withdrawn... Turns out I got the ClientRectangles wrong.
AnswerRe: How do you double buffer the rendering of all form controls? Not just a single control?
Gil.Schmidt
7:23 26 Oct '08  
i would recommand making a "master" function for drawing all the controls in one time and disabling the drawing of a control by itself, maybe even passing a common buffer for each one of the controls to draw them self onto the buffer and draw the whole buffer in one time by the master function when it's ready.

tell me if it helps
Gil
Questionuse double buffer for picturebox ???
ducmanh86
8:23 15 Nov '07  
How do I have write code, if i want to use double buffer for picturebox in form?Confused
AnswerRe: use double buffer for picturebox ???
Gil.Schmidt
0:10 18 Nov '07  
this code is not for the existing controls but for writing your own custom controls.
from .Net 2 there's a double buffer property for the form (it's writtin in the article) i might help but i wouldn't count on it.

hope this helps..

GeneralThank U
dr-Wicked
3:10 20 Feb '07  
subj

dr-Wicked

GeneralGarbage Collection & Dispose
Tomer Noy
22:31 3 Feb '07  
Interesting article, however your handling of memory is problematic.

It is very unrecommended to have objects register to events from the Application class. It is not commonly known, but when you register to an event, that event keeps a reference to your object. This means that as long as the notifying object remains in memory, your object will NOT be garbage collected. In the case of Application, this means that every instance of your control class will remain in memory until the application is shut down!

The proper place to call dispose on any data members that you have on your control is in the control's Dispose method. This method is called when the control's window is destroyed (when its form is closed), or when it is garbage collected.

Some might notice that the Dispose method is auto-generated by the designer when you create a new Form or UserControl, but that doesn't mean you can't alter it. If you cut the method out of the *.designer.cs file, and put it in your code, the code generator will not attempt to recreate it.
QuestionHow can make buffer use Metafile!
quby
5:39 26 Nov '06  
I have tried your program,it worked well!
But there is still problem to use the bitmap as the backbuffer,When the picture size is tremendous,it waste so many memory,and also can't change the it's size! So I want to replace the Bitmap to the Metafile,but can't make it work!D'Oh!
AnswerRe: How can make buffer use Metafile!
Gil_Schmidt
7:02 26 Nov '06  
hi man what`s up?

i`ll love to help but right now i`m travelling in south america for few more months, i`ll be back in march. i don`t deal with any programming right now and i must say that i never used Metafile so i need to check it out to get you an answer. but if you can try to check it out and change the code to see if it works with other formats, the thing is that the data is saved in memory maybe some other format will have better performence but i don`t know about the quality, i guess that it would be better to add some quality picker that would improve the performance instead of high quality graphics (for example a simple progress bar doesn`t need really high quality graphics)

well that`s it for now, hasta luego (until later)
GeneralFlicker still seems to exist
levyuk123
6:10 31 Oct '06  
I've tried the techniques above for my .net 2 app and to be honest the flickering is still present. This might have something to do with 2 forms being open both of which have the OnPaint method overridden. I wouldn't have thought that having two forms open would make such a difference but it does.

Levy
GeneralRe: Flicker still seems to exist
Gil_Schmidt
6:31 31 Oct '06  
hi man..
i don't know how did you write the code but i hope that you've looked at the example that i gave here but from what i've tested it's supposed to work better with the double buffer techniques.
anyway right now i'm in south america so i don't have time to check it out, sorry.. Gil
GeneralThanks
reinux
22:32 4 May '06  
The .NET 2.0 stuff saved my day.

Thanks Smile
GeneralComposite layered graphics
JaseNet
2:47 4 Mar '06  
Nice article Gil.
I have a suggestion/question


With GDI drawing I use a forground and a background device context for applications where the forground changes regularily. The OnPaint blits the background and then the forground but does no operations on the device contexts. Instead all forground drawing is done on OnDraw and background drawing done in InvaliateControl.

As I am new to GDI+ is this something that you could addSmile? Is there an equivalent to BitBlt that would allow blending of forground and background bitmaps to save repeatably drawing the parts of the control that don't change very often?

cheers
Jason
GeneralRe: Composite layered graphics
Gil_Schmidt
10:40 4 Mar '06  
hi JaseNet

am.. i don't know if you read the whole article but what double buffering is doing is to draw the the control graphics into an image in the memory and draw it only one time to the "real" surface of the control this improves the performance, if you'll check out the manual way it also disables the OnPaintBackground event so you draw the foreground and background together on a single paint event there isn't really a background just an event of drawing the control. about drawing parts of the control what the manual way gives you is a full control of the paint event so you don't really have to redraw the whole control each time you can write some code that will draw only the parts the you want.
about BitBlt i never had to use it on C# i used it in VB6 but that was long time ago, i'm sure you can use the API with [DllImport] just look around the net..

Gil
GeneralRe: Composite layered graphics
JaseNet
2:50 5 Mar '06  
Hi Gil
Sorry for the confusion. I am fmiliar with double buffering and have read the article. I was looking for a way of extending it using C#. An example of what I was suggesting...

If you had a control that was dynamic and displayed a scrolling time history for several events such as the cpu usage display then there is a performance benefit in having the background of the control such as grids, axis, rotated text and watermarks predrawn on another drawing surface. The background surface would only change when the control was resized or for example the axis were changed.

The forground drawing surface would only have to contain the dynamic part of the data such as the trace information or rendered display or whatever. This would typically involve displaying a lot of data, say 4 times a second.
As GDI+ is not hardware accelerated it seemed like a good idea to adopt the GDI approach and use two surfaces. For most of the time no drawing would happen on the background surface, only the forground so the cpu is not wasting time constantly drawing all of the display, only the parts that changed.

I accept what you are saying about only updating the invalidated regions but in reality this would end up invalidating most, if not all of the display.Smile

I have looked at alpha blending the two surfaces but the performance hit on GDI+ is too expensive.

thanks

Jason


GeneralRe: Composite layered graphics
Gil_Schmidt
3:01 5 Mar '06  
hi again


well i think this is a good idea but it depends very much on the solution that is being built, and what i aimed for in this article is for the general use of the techniques of double buffering, your suggesting is very good and will surly be fitted in complex graphic project but in simple projects like a progress bar i don't know if it's worth the spending of time for it but on the next update for the article i'll mention it as a possibility.

i appreciate your comment Gil
GeneralPossible solution?
ITGFanatic
8:27 30 Oct '06  
I had to do something similar recently.

GDI+ gradients are a very computationally expensive procedure. I had a few gradient circles, and drawing them each frame killed the app. So I rendered the gradient circles into a bitmap object using Graphics.FromImage(Bitmap), and then stored the image away in memory.

Then, whenever any individual part of my control needed repainting, I would use the PaintEventArgs.Graphics.DrawImage() method (which I've read somewhere is just a bit slower than bitblt), but I would make the source/destination Rectangles equal to the clipping Rectangle. This way, I would only draw the background image where Windows told me it needed drawn.

Then, after drawing the image, you just render the rest of your dynamic information with e.g. DrawString() etc after having done DrawImage().

The final piece of the puzzle is to intelligently Invalidate(). If you Invalidate() the whole form, DrawImage() will draw the whole bitmap. But if you know that your e.g. CPU usage graph needs to be updated, just Invalidate() the Rectangle that holds the graph. For extra performance, make something like a background Region, and if the clipping Rectangle doesn't intersect at all with the background Region, you don't even need to call DrawImage().

Hope some of that helped...
Generalmissing AssemblyInfo.cs from download
JaseNet
2:02 4 Mar '06  
Nice article but the download won't compile Smileas AssemblyInfo.cs is missing.. Cut and paste this for now




using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("DoubleBufferExample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DoubleBufferExample")]
[assembly: AssemblyCopyright("Copyright © 2005")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e5fa6eb1-2959-4d33-84dc-0178b1f8743a")]

// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]

GeneralVery nice article!
rippo
21:57 7 Feb '06  
Brings me back to the good old amiga days! Double buffering was the buzz word back then.

This is just what I have been looking for
GeneralBenchmarking
Mikael Wiberg
22:12 31 Jan '06  
Have you done any benchmarking concerning the time it takes to do the rendering using the different double-buffer techniques you have presented?
Maybe you could include this in your test application?
Source code for the test application would be great too.

It could be worth mentioning the huge performance impact that you get if you use DrawImage instead of DrawImageUnscaled. Or maybe this doesn't apply in .NET 2 using OptimizedDoubleBuffer?

Good work.


Last Updated 1 Feb 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010