Friday, September 30, 2005

Flickerfree painting in .NET

Suppressing flicker while painting windows in .NET is horribly similar to Win32 and MFC.
Suppress the background draw, paint to a bitmap in memory and bitblt it to the window.

The main difference is that the whole process can be encapsulated neatly.
Here is the interface you’ll need to implement and a reusable class that does the double buffered drawing. Note the line that does 2DSmoothing (anti-aliasing).




using System;
using System.Drawing;

namespace Cunning.UI.Utilities
{
public interface IPaintDoubleBuffered
{
Size GetSize();
Graphics GetGraphics();
void PaintDoubleBuffered(Graphics g);
}

public sealed class DoubleBufferedPaint
{
private DoubleBufferedPaint(){}

public static void Paint(IPaintDoubleBuffered control)
{
if(null == control)
throw new ArgumentException("control");

Graphics controlGraphics = control.GetGraphics();
Size controlSize = control.GetSize();
Bitmap bitmap = new Bitmap(controlSize.Width, controlSize.Height, control.GetGraphics());
Graphics bitmapGraphics = Graphics.FromImage(bitmap);

// sets 2D smoothing to anti-alias drawing
bitmapGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;

// do painting
control.PaintDoubleBuffered(bitmapGraphics);

controlGraphics.DrawImageUnscaled(bitmap, 0, 0);
bitmapGraphics.Dispose();
}
}
}



Here is a sample implementation of the drawing routines you’ll need to write and an empty overridden OnPaintBackground method to help suppress the flicker.



#region IPaintDoubleBuffered Members

public Size GetSize()
{
return this.ClientSize;
}

public Graphics GetGraphics()
{
return this.CreateGraphics();
}

public void PaintDoubleBuffered(Graphics g)
{
// put your drawing routine in here using the Graphics object provided
PaintBackground(g);
DrawMarker(g);
DrawProgressString(g);
}

#endregion

protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs args)
{
// Do nothing here to help prevent flicker
}


Now we can execute the double buffered painting in our PaintEventHandler with a rather elegant implementation.



private void ProgressControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
DoubleBufferedPaint.Paint(this);
}

No comments: