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

ste*_*enj 27 .net c# performance winforms

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

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

在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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

我该怎么办?

Ada*_*son 43

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
}
Run Code Online (Sandbox Code Playgroud)

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


小智 5

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