首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Winforms:挂起布局/ResumeLayout还不够吗?

Winforms:挂起布局/ResumeLayout还不够吗?
EN

Stack Overflow用户
提问于 2009-05-07 14:47:30
回答 10查看 41.7K关注 0票数 28

我有一个包含一些“自定义控件”的库。本质上,我们有自己的按钮,圆角面板,以及一些带有一些自定义绘画的分组框。尽管OnPaint方法中存在“数学”问题,但这些控件都是相当标准的。大多数情况下,我们所要做的就是绘制圆角,并在背景中添加渐变。我们使用GDI+来完成所有这些工作。

这些控件都很好(根据我们的客户的说法非常漂亮),但是尽管有DoubleBuffer,你还是可以看到一些重绘,特别是当在同一个窗体上有20++按钮(例如)的时候。在表单加载时,您会看到绘制…的按钮这很烦人。

我很确定我们的按钮不是地球上最快的东西,但我的问题是:如果双缓冲是“开”的,那么所有的重绘不应该在后台发生,Windows子系统应该“立即”显示结果吗?

另一方面,如果有一个“复杂的”foreach循环,可以创建标签,将它们添加到面板(双缓冲)并改变它们的属性,如果我们在循环之前暂停面板的布局,并在循环结束后恢复面板的布局,那么所有这些控件(标签和按钮)不是应该“几乎立即”出现吗?这不是那样发生的,你可以看到面板被填满了。

你知道为什么这种情况没有发生吗?我知道没有示例代码很难评估,但这也很难复制。我可以用摄像头做视频,但相信我,它不是很快:)

EN

回答 10

Stack Overflow用户

发布于 2009-05-07 15:03:32

我们也看到过这个问题。

我们已经看到的一种“修复”方法是完全暂停绘制控件,直到我们准备好为止。为此,我们将WM_SETREDRAW消息发送到控件:

代码语言:javascript
复制
// 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);
票数 13
EN

Stack Overflow用户

发布于 2009-05-18 18:30:16

您应该注意的一件事是,您是否在面板的任何子控件上设置了BackColor=Transparent。BackColor=Transparent将显着降低渲染性能,尤其是在父面板使用渐变的情况下。

Windows窗体不使用真正的透明,而是使用“假”透明。每个子控件paint调用都会在父控件上生成paint调用,以便父控件可以绘制其背景,子控件在该背景上绘制其内容,以使其显示为透明。

因此,如果您有50个子控件,这将在父控件上生成额外的50个绘制调用,以进行背景绘制。由于渐变通常较慢,因此您将看到性能下降。

希望这能有所帮助。

票数 13
EN

Stack Overflow用户

发布于 2009-05-07 16:37:04

我将从性能的角度来解决您的问题。

将创建标签、将标签添加到面板(双缓冲)并更改其属性的

foreach循环

如果这就是事情完成的顺序,那么还有改进的空间。首先创建所有标签,更改它们的属性,当它们都准备就绪时,将它们添加到面板中:Panel.Controls.AddRange(Control[])

大多数时候,我们所要做的就是绘制圆角和添加渐变到背景

你是不是一遍又一遍地做同样的事情?您的渐变是如何生成的?写一张图片不可能那么慢。我曾经不得不在内存中创建一个1680x1050的渐变,它真的很快,对Stopwatch来说太快了,所以绘制一个渐变不会那么难。

我的建议是尝试缓存一些东西。打开画图,绘制您的角落并保存到磁盘,或在内存中生成图像只需一次。然后根据需要加载(并调整大小)。渐变也是如此。

即使不同的按钮具有不同的颜色,但主题相同,您也可以使用Paint或其他工具创建一个位图,并在运行时加载它并将颜色值乘以另一种颜色。

编辑:

如果我们在循环之前暂停面板的布局,并在循环结束时恢复面板的布局,则为

这不是SuspendLayout和ResumeLayout的用途。它们挂起布局逻辑,即控件的自动定位。与FlowLayoutPanel和TableLayoutPanel最相关。

至于双缓冲,我不确定它是否适用于自定义绘制代码(还没有尝试过)。我想你应该实现你自己的。

Doublebuffering简而言之:它非常简单,只有几行代码。在paint事件中,渲染到位图而不是渲染到Graphics对象,然后将该位图绘制到Graphics对象。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/835100

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档