Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Own WinForms Control Flickers and Has Bad Performance

I have two problems with an own user control which uses bitmaps:

  1. It flickers if it's redrawn via .NET's 'Refresh' method.
  2. It has a bad performance.

The control consists of three bitmaps:

  • A static background image.
  • A rotating rotor.
  • Another image depending on rotor angle.

All used bitmaps have a resolution of 500x500 pixels. The control works like this: https://www.dropbox.com/s/t92gucestwdkx8z/StatorAndRotor.gif (it's a gif animation)

The user control should draw itself everytime it gets a new rotor angle. Therefore, it has a public property 'RotorAngle' which looks like this:

public double RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Refresh();
    }
}

Refresh raises the Paint event. The OnPaint event handler looks like this:

private void StatorAndRotor2_Paint(object sender, PaintEventArgs e)
{
    // Draw the three bitmaps using a rotation matrix to rotate the rotor bitmap.
    Draw((float)mRotorAngle);
}

But when I use this code - which works well in other own user controls - the user control is not drawn at all if control is double buffered via SetStyle(ControlStyles.OptimizedDoubleBuffer, true). If I don't set this flag to true, the control flickers when being redrawn.

In control constructor I set:

SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ContainerControl, false);
// User control is not drawn if "OptimizedDoubleBuffer" is true.
// SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);

First, I thought it flickers because the background is cleared everytime the control is drawn. Therefore, I set SetStyle(ControlStyles.AllPaintingInWmPaint, true). But it didn't help.

So, why does it flicker? Other controls work very well with this setup. And why is the controly not drawn if SetStyle(ControlStyles.OptimizedDoubleBuffer, true).

I found out that the control does not flicker if I invoke my Draw method directly after changing the property RotorAngle:

public float RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Draw(mRotorAngle);
    }
}

But this results in a very bad performance, especially in full screen mode. It's not possible to update the control every 20 milliseconds. You can try it yourself. I will attach the complete Visual Studio 2008 solution below.

So, why it is such a bad performance? It's no problem to update other (own) controls every 20 milliseconds. Is it really just due to the bitmaps?

I created a simple visual Visual Studio 2008 solution to demonstrate the two problems: https://www.dropbox.com/s/mckmgysjxm0o9e0/WinFormsControlsTest.zip (289,3 KB)

There is an executable in directory bin\Debug.

Thanks for your help.

like image 223
Benedikt Avatar asked May 14 '12 14:05

Benedikt


1 Answers

First, per LarsTech's answer, you should use the Graphics context provided in the PaintEventArgs. By calling CreateGraphics() inside the Paint handler, you prevent OptimizedDoubleBuffer from working correctly.

Second, in your SetStyle block, add:

SetStyle( ControlStyles.Opaque, true );

... to prevent the base class Control from filling in the background color before calling your Paint handler.

I tested this in your example project, it seemed to eliminate the flickering.

like image 118
lnmx Avatar answered Sep 20 '22 17:09

lnmx