【问题标题】:Windows Forms: using BackgroundImage slows down drawing of the Form's controlsWindows 窗体:使用 BackgroundImage 会减慢窗体控件的绘制速度
【发布时间】:2010-10-21 03:44:52
【问题描述】:

我有一个 Windows 窗体 (C# .NET 3.5),上面有许多按钮和其他控件,所有这些都分配给跨越整个窗体的最顶层面板。比如层次结构是:Form -> Panel -> 其他控件。

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

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

当然,我尝试过使用DoubleBuffered = true,并且我还使用反射在所有控件上设置了它,但没有效果。

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

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,看看是否有什么不同。此外,图像的大小为 1024x768,但较小的图像具有相同的减速效果(虽然稍微小一些)。

我该怎么办?

【问题讨论】:

标签: c# .net winforms performance


【解决方案1】:

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 实例上的扩展方法。

【讨论】:

  • 它没有帮助......我还注意到,当弹出菜单覆盖一些按钮并强制它们重绘时,重绘特别慢(例如,您看到按钮边框已绘制,按钮已填充用纯色,最后按钮绘制它的图片,然后跟随下一个按钮)。
  • 这实际上给了我巨大的性能提升!我在单个控件上有大约 60 个标签,放置在表格布局面板中。列被设置为自动调整大小,这需要花费大量时间来重新渲染。这个技巧似乎会暂停绘图,直到布局完成,消除烦人的可见重绘。
  • 这对我的 user_control 也有很大影响。谢谢!
  • 哇,有什么不同!谢谢亚当!!
  • 嗨,你能帮我看看这个怎么用吗?谢谢
【解决方案2】:

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

【讨论】:

  • 我尝试了很多东西。作为最后一个,我想试一试,它出人意料地对我有用。显着差异...谢谢
【解决方案3】:

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

panelParent.visible = false;

for(...) {
    // Add your controls here:
    panelParent.Controls.Add(...);
}

panelParent.visible = true;

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 您能详细说明一下吗?我正在为类似的问题尝试此解决方案,除了我没有添加控件,而是在表单上绘图。包含图像的图片框消除了绘制时的滞后,但现在我不再在表单上看到我的绘制图形。
    • @BobbyByrnes 你也可以在图片上画画(使用 Paint 事件为 PictureBox)
    【解决方案5】:

    对我来说,帖子 Form load is slow if adding a background image 解决了这个问题:

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

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

    【讨论】:

    • 尽管我的表单有一个固定的大小来匹配图像大小,但 Tile 的默认 BackgroundImageLayout 是罪魁祸首。将其更改为拉伸并解决了问题。
    【解决方案6】:

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

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

    每次绘制面板网格(包括调整大小)大约需要一秒钟 - 不错但非常明显,并且在较慢的机器上存在可用性问题。

    我的图片不是很大,但有些过大。

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

    事后看来,这是一个明显的优化...一次调整 8 张图像的大小,而不是重复 156 次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      • 1970-01-01
      • 2014-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多