自己的WinForms控件闪烁并且性能不佳

Ben*_*ikt 6 c# performance user-controls flicker winforms

我有一个使用位图的自己的用户控件有两个问题:

  1. 如果通过.NET的'Refresh'方法重新绘制它会闪烁.
  2. 它表现不佳.

该控件由三个位图组成:

  • 静态背景图像.
  • 旋转的转子.
  • 另一个图像取决于转子角度.

所有使用的位图都具有500x500像素的分辨率.控件的工作方式如下:https: //www.dropbox.com/s/t92gucestwdkx8z/StatorAndRotor.gif(这是一个gif动画)

每次获得新的转子角度时,用户控件应自行绘制.因此,它有一个公共属性'RotorAngle',如下所示:

public double RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Refresh();
    }
}
Run Code Online (Sandbox Code Playgroud)

Refresh提出这Paint件事.该OnPaint事件处理程序是这样的:

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

但是当我使用这个代码 - 在其他用户控件中运行良好时 - 如果控件是双缓冲的,则根本不会绘制用户控件SetStyle(ControlStyles.OptimizedDoubleBuffer, true).如果我没有将此标志设置为true,则重绘时控件会闪烁.

在控件构造函数中我设置:

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);
Run Code Online (Sandbox Code Playgroud)

首先,我认为它会闪烁,因为每次绘制控件时背景都会被清除.所以,我订了SetStyle(ControlStyles.AllPaintingInWmPaint, true).但它没有帮助.

那么,它为什么会闪烁?其他控件在此设置下运行良好.为什么如果没有绘制控制SetStyle(ControlStyles.OptimizedDoubleBuffer, true).

我发现如果我Draw在更改属性后直接调用我的方法,控件不会闪烁RotorAngle:

public float RotorAngle
{
    get { return mRotorAngle; }
    set
    {
        mRotorAngle = value;
        Draw(mRotorAngle);
    }
}
Run Code Online (Sandbox Code Playgroud)

但这会导致非常糟糕的性能,尤其是在全屏模式下.每20毫秒无法更新控件.你可以自己试试.我将在下面附上完整的Visual Studio 2008解决方案.

那么,为什么表现如此糟糕呢?每20毫秒更新一次(自己的)控件没问题.它真的只是由于位图?

我创建了一个简单的Visual Visual Studio 2008解决方案来演示这两个问题: https://www.dropbox.com/s/mckmgysjxm0o9e0/WinFormsControlsTest.zip(289,3 KB)

目录中有一个可执行文件bin\Debug.

谢谢你的帮助.

lnm*_*nmx 4

首先,根据 LarsTech 的回答,您应该Graphics使用PaintEventArgs. 通过在处理程序CreateGraphics()内部调用Paint,您将无法OptimizedDoubleBuffer正常工作。

其次,在 SetStyle 块中添加:

SetStyle( ControlStyles.Opaque, true );
Run Code Online (Sandbox Code Playgroud)

...以防止基类 Control 在调用 Paint 处理程序之前填充背景颜色。

我在你的示例项目中对此进行了测试,它似乎消除了闪烁。