Getting rid of flickering in .NET CF forms with custom drawn controls
Feb 13, 2011 | 42Gears Team
.NET Compact Framework doesnt provide builtin double buffering for forms. In case you have multiple custom drawn user controls on a form, loading will mostly show flickr. Overriding OnPaint and drawing the form and its child controls to an offscreen bitmap before putting it out to actual display is expected to solve this. But, once a child control is added to another container control, overriding OnPaint of the parent container control doesnt allow you to paint the child as the child’s client rect is clipped out from the graphics object passed to parent’s OnPaint.
The solution to this problem is to avoid adding the custom user control to the forms. Instead, maintain your own list of such controls. Form’s constructor should make these changes.
//this.Controls.Add(customControl); //don't do this
control_list.Add(customControl); //control_list is Forms own custom list for it's child controls.
When we do that, GWES doesn’t know of these controls as child to our form and hence allows us to paint anywhere we like. We can now paint all child controls (by calling their respective OnPaint) to an offscreen bitmap before blting it to actual display. Heres a sample code which does something like this.
protected override void OnPaint(PaintEventArgs e)
{
using (Bitmap doubleBuffer = new Bitmap(this.Width, this.Height))
{
using (Graphics gxOff = Graphics.FromImage(doubleBuffer))
{
using (Brush backBrush = new SolidBrush(this.BackColor))
{
gxOff.FillRectangle(backBrush, this.ClientRectangle);
}
foreach (CustomControl ctl in control_list) //control_list is list of child controls maintained by Form
{
Rectangle rc = new Rectangle(ctl.Left, ctl.Top, ctl.Width, ctl.Height);
if (e.ClipRectangle.IntersectsWith(rc)) //update only those child control which fall within the invalidated region
{
ctl.OnPaint(new PaintEventArgs(gxOff, ctl.ClientRectangle), ctl.Left, ctl.Top);
}
}
e.Graphics.DrawImage(doubleBuffer, 0, 0);
}
}
}
This scheme, however, also requires the form to manage and delegate other GWES events (keypress, clicks, etc) to respective child control. Following code snippet shows that for MouseDown
protected override void OnMouseDown(MouseEventArgs e)
{
foreach (CustomControl ctl in control_list)
{
Rectangle rc = new Rectangle(ctl.Left, ctl.Top, ctl.Width, ctl.Height);
if (rc.Contains(new Point(e.X, e.Y)))
{
ctl.OnMouseDown(e);
this.Invalidate(rc);
break;
}
}
}
I know its a bit of pain but in case you have simple custom controls like buttons, picturebox, very few events need to be overridden and its worth for the flickr free smooth rendering of your forms.