我有一个包含一些“自定义控件”的库。本质上,我们有自己的按钮,圆角面板,以及一些带有一些自定义绘画的分组框。尽管OnPaint方法中存在“数学”问题,但这些控件都是相当标准的。大多数情况下,我们所要做的就是绘制圆角,并在背景中添加渐变。我们使用GDI+来完成所有这些工作。
这些控件都很好(根据我们的客户的说法非常漂亮),但是尽管有DoubleBuffer,你还是可以看到一些重绘,特别是当在同一个窗体上有20++按钮(例如)的时候。在表单加载时,您会看到绘制…的按钮这很烦人。
我很确定我们的按钮不是地球上最快的东西,但我的问题是:如果双缓冲是“开”的,那么所有的重绘不应该在后台发生,Windows子系统应该“立即”显示结果吗?
另一方面,如果有一个“复杂的”foreach循环,可以创建标签,将它们添加到面板(双缓冲)并改变它们的属性,如果我们在循环之前暂停面板的布局,并在循环结束后恢复面板的布局,那么所有这些控件(标签和按钮)不是应该“几乎立即”出现吗?这不是那样发生的,你可以看到面板被填满了。
你知道为什么这种情况没有发生吗?我知道没有示例代码很难评估,但这也很难复制。我可以用摄像头做视频,但相信我,它不是很快:)
发布于 2009-05-07 15:03:32
我们也看到过这个问题。
我们已经看到的一种“修复”方法是完全暂停绘制控件,直到我们准备好为止。为此,我们将WM_SETREDRAW消息发送到控件:
// Note that WM_SetRedraw = 0XB
// Suspend drawing.
UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
...
// Resume drawing.
UnsafeSharedNativeMethods.SendMessage(handle, WindowMessages.WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);发布于 2009-05-18 18:30:16
您应该注意的一件事是,您是否在面板的任何子控件上设置了BackColor=Transparent。BackColor=Transparent将显着降低渲染性能,尤其是在父面板使用渐变的情况下。
Windows窗体不使用真正的透明,而是使用“假”透明。每个子控件paint调用都会在父控件上生成paint调用,以便父控件可以绘制其背景,子控件在该背景上绘制其内容,以使其显示为透明。
因此,如果您有50个子控件,这将在父控件上生成额外的50个绘制调用,以进行背景绘制。由于渐变通常较慢,因此您将看到性能下降。
希望这能有所帮助。
发布于 2009-05-07 16:37:04
我将从性能的角度来解决您的问题。
将创建标签、将标签添加到面板(双缓冲)并更改其属性的
foreach循环
如果这就是事情完成的顺序,那么还有改进的空间。首先创建所有标签,更改它们的属性,当它们都准备就绪时,将它们添加到面板中:Panel.Controls.AddRange(Control[])
大多数时候,我们所要做的就是绘制圆角和添加渐变到背景
你是不是一遍又一遍地做同样的事情?您的渐变是如何生成的?写一张图片不可能那么慢。我曾经不得不在内存中创建一个1680x1050的渐变,它真的很快,对Stopwatch来说太快了,所以绘制一个渐变不会那么难。
我的建议是尝试缓存一些东西。打开画图,绘制您的角落并保存到磁盘,或在内存中生成图像只需一次。然后根据需要加载(并调整大小)。渐变也是如此。
即使不同的按钮具有不同的颜色,但主题相同,您也可以使用Paint或其他工具创建一个位图,并在运行时加载它并将颜色值乘以另一种颜色。
编辑:
如果我们在循环之前暂停面板的布局,并在循环结束时恢复面板的布局,则为
这不是SuspendLayout和ResumeLayout的用途。它们挂起布局逻辑,即控件的自动定位。与FlowLayoutPanel和TableLayoutPanel最相关。
至于双缓冲,我不确定它是否适用于自定义绘制代码(还没有尝试过)。我想你应该实现你自己的。
Doublebuffering简而言之:它非常简单,只有几行代码。在paint事件中,渲染到位图而不是渲染到Graphics对象,然后将该位图绘制到Graphics对象。
https://stackoverflow.com/questions/835100
复制相似问题