【发布时间】:2012-05-22 01:56:03
【问题描述】:
我自己的使用位图的用户控件有两个问题:
- 如果通过 .NET 的“刷新”方法重绘,它会闪烁。
- 性能很差。
该控件由三个位图组成:
- 静态背景图片。
- 一个旋转的转子。
- 另一个取决于转子角度的图像。
所有使用的位图的分辨率均为 500x500 像素。该控件的工作原理如下: https://www.dropbox.com/s/t92gucestwdkx8z/StatorAndRotor.gif(是gif动画)
用户控件应在每次获得新的转子角度时自行绘制。因此,它有一个公共属性“RotorAngle”,如下所示:
public double RotorAngle
{
get { return mRotorAngle; }
set
{
mRotorAngle = value;
Refresh();
}
}
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);
}
但是当我使用这段代码时——它在其他自己的用户控件中运行良好——如果控件通过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);
首先,我认为它会闪烁,因为每次绘制控件时都会清除背景。因此,我设置了SetStyle(ControlStyles.AllPaintingInWmPaint, true)。但这没有帮助。
那么,为什么会闪烁?其他控件在此设置下工作得很好。如果SetStyle(ControlStyles.OptimizedDoubleBuffer, true),为什么不绘制控件。
我发现如果在更改属性RotorAngle 后直接调用我的Draw 方法,控件不会闪烁:
public float RotorAngle
{
get { return mRotorAngle; }
set
{
mRotorAngle = value;
Draw(mRotorAngle);
}
}
但这会导致性能非常差,尤其是在全屏模式下。不可能每 20 毫秒更新一次控件。你可以自己试试。我将在下面附上完整的 Visual Studio 2008 解决方案。
那么,为什么它的表现如此糟糕?每 20 毫秒更新一次其他(自己的)控件是没有问题的。真的只是位图的原因吗?
我创建了一个简单的 Visual Studio 2008 解决方案来演示这两个问题: https://www.dropbox.com/s/mckmgysjxm0o9e0/WinFormsControlsTest.zip (289,3 KB)
目录bin\Debug中有一个可执行文件。
感谢您的帮助。
【问题讨论】:
-
我现在无法详细介绍所有细节,但您需要查看双缓冲。幸运的是,它在 2008+ 中非常简单您在属性中进行刷新的方式也很糟糕。
-
如果您的应用程序可能在远程桌面上使用,请不要双缓冲 - 请参阅 this link。您可以检查当前会话是否为远程桌面:
if (SystemInformation.TerminalServerSession) ...
标签: c# winforms performance user-controls flicker