Windows窗体:使用BackgroundImage会减慢窗体控件的绘制速度

我有一个Windows窗体(C#.NET 3.5),上面有许多按钮和其他控件,全部分配给一个跨越整个窗体的最顶层面板。 例如,层次结构为:Form – > Panel – >其他控件。

一旦我将BackgroundImage分配给Panel,控件就会非常缓慢地绘制。 如果我使用Form的BackgroundImage属性并将Panel的BackgroundColor设置为“transparent”,我会有同样的效果。 看起来好像首先绘制了具有背景的窗口,然后在绘制下一个控件之前稍微延迟逐个添加每个控件。 换句话说,您实际上可以按照每个控件绘制到窗体的顺序。 一旦所有控件都被绘制,一旦此效果不再发生,但表单的响应性仍然很慢。

在Visual Studio的设计器中,我得到了相同的效果,尤其是在移动控件时。 有时表单的绘图完全停止一两秒,这使得在设计器和生成的应用程序中使用BackgroundImage是一个完全的拖拽。

当然,我尝试使用DoubleBuffered = true,我也使用reflection在所有控件上设置它,没有任何效果。

此外,这里是加载代码的表单,因为它有点不寻常。 它将所有控件从另一个表单复制到当前表单上。 这样做是为了能够使用设计者分别编辑每个屏幕的视觉外观,同时共享通用表单和公共代码基础。 我预感它可能是减速的原因,但它仍然无法解释为什么减速器已经在设计师中引人注目。

private void LoadControls(Form form) { this.SuspendLayout(); this.DoubleBuffered = true; EnableDoubleBuffering(this.Controls); this.BackgroundImage = form.BackgroundImage; this.BackColor = form.BackColor; this.Controls.Clear(); foreach (Control c in form.Controls) { this.Controls.Add(c); } this.ResumeLayout(); } 

如您所见, SuspendLayout()ResumeLayout()用于避免不必要的重绘。

尽管如此,一旦使用BackgroundImage,表单就像“地狱一样慢”。 我甚至尝试将其转换为PNG,JPG和BMP,看看是否有任何区别。 此外,图像尺寸为1024×768,但较小的图像具有相同的减速效果(尽管略小)。

我该怎么办?

SuspendLayout()ResumeLayout()不会挂起绘图,只挂起布局操作。 给这个家伙一个机会:

 public static class ControlHelper { #region Redraw Suspend/Resume [DllImport("user32.dll", EntryPoint = "SendMessageA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); private const int WM_SETREDRAW = 0xB; public static void SuspendDrawing(this Control target) { SendMessage(target.Handle, WM_SETREDRAW, 0, 0); } public static void ResumeDrawing(this Control target) { ResumeDrawing(target, true); } public static void ResumeDrawing(this Control target, bool redraw) { SendMessage(target.Handle, WM_SETREDRAW, 1, 0); if (redraw) { target.Refresh(); } } #endregion } 

用法应该是不言自明的,语法与SuspendLayout()ResumeLayout() 。 这些是将在任何Control实例上显示的扩展方法。

我也遇到了同样的问题,可以通过降低背景图片的分辨率来解决它。 当您使用大尺寸(例如:1280X800)图片作为背景时,在表格上绘制控件需要一些时间。 最好在“Paint”中打开图片,尺寸小于表格,然后以“bmp”格式保存。 现在尝试将此图片添加为表单的背景。

另一种在添加控件时避免永久重绘的非常简单的方法是在向其添加控件之前使父控件不可见。 之后,您可以使父控件(例如,面板)可见,并且没有所有这些重绘。 🙂

 panelParent.visible = false; for(...) { // Add your controls here: panelParent.Controls.Add(...); } panelParent.visible = true; 

我使用PictureBox解决了同样的问题。 只需将PictureBox添加到容器中,选择“将其停靠在父容器中”(或属性Dock = Fill )并将其设置为Image。 它看起来就像父控件的BackGroundImage。

对我来说, 如果添加背景图像解决了问题,则表单加载速度很慢

确保您的backgroundcolor未设置为“透明”。 将其设置为“白色”以获得更好的性能。

另外,将BackgroundImageLayout设置为“Center”或“ Stretch ”以提高性能。 这将启用表单上的双缓冲区。

我意识到这是一个旧线程,但我在搜索相同问题的信息时发现它,所以如果它在某些时候对某人有用:

我的情况:我有一个13 x 12的面板网格,它们动态设置背景图像,并根据用户选择定期更改。 每个Panel还添加了一个文本标签控件。 为了使文本覆盖背景图像,必须将其设置为透明(顺便说一下 – 我的经验是Zoom,Stretch,Center的BackgroundImageLayout几乎没有效果。背景颜色设置为透明或白色也没什么效果)。

面板网格的每次抽取(包括resize)大约需要一秒钟 – 不是很差但很明显,而且在较慢的机器上可用性问题。

我的图像并不大,但有点过大。

我发现:通过在设置backgroundimage之前将我的图像集调整到精确的面板大小,绘制时间显着下降 – 大约0.1秒。 由于我的程序根据窗口大小动态调整面板大小,因此在设置156个面板的背景之前,我会在windows resize事件上动态调整一次图像集。

事后看来,它是一个明显的优化……一次调整8个图像,而不是重复156次。