Flicker free rendering


I have seen a few different ways to achieve 100% flicker free rendering in custom controls. Some work and some don't. Here is a method that I have used on my projects to provide my clients with beautiful, easy to use controls.

The way we achieve this is we draw both the background and the foreground to a buffer, and then draw that buffer to the screen in one go. Its a very simple technique that only requires a bitmap to use as a buffer, and you override three methods, OnResize, OnPaintBackgroundand OnPaint.

First we need the buffer, which should be a class variable as such

private Bitmap buffer = null;

The buffer only needs to be rebuilt when the control is created and when its resized. This is why we overload the OnResize method. Here we will dispose of the current buffer if needed and create the new with the current controls size, but only if both the width and height are greater than 0, otherwise it will throw an error if it tries.

protected override void OnResize(EventArgs e)
{    
    base.OnResize(e);    
    if (this.Width > 0 && this.Height > 0)    
    {        
        if (this.buffer != null)            
            this.buffer.Dispose();        
        this.buffer = new Bitmap(this.Width, this.Height);    
    }    
    // make sure it redraws on resize    
    this.Invalidate();

}

The OnResize method will be called before the control is shown, so this will initialise the buffer as well. 

Painting the background of the control is done in the OnPaintBackground method of course. This is where most of the flickering will occur as it tries to clear the control first. We don't want it to do this, but if we simply override the method and don't call the base implementation then the control will not be rendered correctly. So instead we discard the provided PaintEventArgs, and pass in one of our own.

protected override void OnPaintBackground(PaintEventArgs e)
{
    Graphics g = Graphics.FromImage(buffer);
     PaintEventArgs ex = new PaintEventArgs(g, e.ClipRectangle);
    base.OnPaintBackground(ex);
}

Now the control will paint the background to our buffer instead of directly to the screen. The only thing left to do is to do your custom drawing, which can all be done in the OnPaint method with a little extra code to display the buffer at the end.

protected override void OnPaint(PaintEventArgs e)
{
    Graphics gB = Graphics.FromImage(buffer);
    // do any drawing you need to here to gB
    // the clipping on the provided graphics object can create
    // some refresh artefacts so I always use a new graphics object
    Graphics gM = this.CreateGraphics();
     gM.DrawImage(buffer, new Point(0, 0));
    gM.Dispose();
    gB.Dispose();
}

All of your drawing is still done on the buffer, and once your finished you draw the buffer on the control using a new instance of its Graphics object with the DrawImage method.

I hope this helps you create more professional looking controls and interfaces. For a working example, please find the scrollable label at my blog www.code-dragon.com which includes a test form you can play around with.


Similar Articles