C# 为什么我的WinForms控件闪烁并缓慢调整大小?

C# 为什么我的WinForms控件闪烁并缓慢调整大小?,c#,winforms,controls,resize,flicker,C#,Winforms,Controls,Resize,Flicker,我正在制作一个程序,其中我有很多面板和面板中的面板 我在这些面板中有一些自定义绘制的控件 1面板的调整大小功能包含用于调整该面板中所有控件的大小和位置的代码 现在,只要我调整程序的大小,这个面板的大小就会被激活。这会导致此面板中的组件大量闪烁 所有用户绘制的控件都是双缓冲的 有人能帮我解决这个问题吗?也许对你来说,一个好的解决办法就是使用和事件 调整大小时将主面板可见性设置为false,调整大小时将主面板可见性设置为true 这样,当有人调整表单大小时,面板将不会重新绘制。查看您发布的项目,当您

我正在制作一个程序,其中我有很多面板和面板中的面板

我在这些面板中有一些自定义绘制的控件

1面板的调整大小功能包含用于调整该面板中所有控件的大小和位置的代码

现在,只要我调整程序的大小,这个面板的大小就会被激活。这会导致此面板中的组件大量闪烁

所有用户绘制的控件都是双缓冲的


有人能帮我解决这个问题吗?

也许对你来说,一个好的解决办法就是使用和事件

调整大小时将主面板可见性设置为false,调整大小时将主面板可见性设置为true


这样,当有人调整表单大小时,面板将不会重新绘制。

查看您发布的项目,当您选择第一个选项卡时,渐变填充组框的闪烁效果非常糟糕。随着第二个或第三个标签的显示,几乎没有任何闪烁,如果有的话

很明显,问题与您在选项卡页面上显示的控件有关。快速浏览一下自定义渐变填充分组框类的代码,就会发现更具体的原因。每次绘制一个groupbox控件时,都要进行大量非常昂贵的处理由于每次调整表单大小时,每个groupbox控件都必须重新绘制自身,因此该代码的执行次数令人难以置信。

另外,您将控件的背景设置为“透明”,这必须在WinForms中通过要求父窗口首先在控件窗口内绘制自身来生成背景像素来伪造。然后,控件将自己绘制在该控件之上。这也比用纯色(如
SystemColors.control
)填充控件的背景要复杂得多,这会使您在调整窗体大小时看到正在绘制的窗体像素,而此时GroupBox才有机会自己绘制

下面是我在自定义渐变填充groupbox控件类中讨论的特定代码:

protected override void OnPaint(PaintEventArgs e)
{
    if (Visible)
    {
        Graphics gr = e.Graphics;
        Rectangle clipRectangle = new Rectangle(new Point(0, 0), this.Size);
        Size tSize = TextRenderer.MeasureText(Text, this.Font);
        Rectangle r1 = new Rectangle(0, (tSize.Height / 2), Width - 2, Height - tSize.Height / 2 - 2);
        Rectangle r2 = new Rectangle(0, 0, Width, Height);
        Rectangle textRect = new Rectangle(6, 0, tSize.Width, tSize.Height);

        GraphicsPath gp = new GraphicsPath();
        gp.AddRectangle(r2);
        gp.AddRectangle(r1);
        gp.FillMode = FillMode.Alternate;

        gr.FillRectangle(new SolidBrush(Parent.BackColor), clipRectangle);

        LinearGradientBrush gradBrush;
        gradBrush = new LinearGradientBrush(clipRectangle, SystemColors.GradientInactiveCaption, SystemColors.InactiveCaptionText, LinearGradientMode.BackwardDiagonal);
        gr.FillPath(gradBrush, RoundedRectangle.Create(r1, 7));

        Pen borderPen = new Pen(BorderColor);
        gr.DrawPath(borderPen, RoundedRectangle.Create(r1, 7));
        gr.FillRectangle(gradBrush, textRect);
        gr.DrawRectangle(borderPen, textRect);
        gr.DrawString(Text, base.Font, new SolidBrush(ForeColor), 6, 0);
    }

}

protected override void OnPaintBackground(PaintEventArgs pevent)
{
    if (this.BackColor == Color.Transparent)
        base.OnPaintBackground(pevent);
}
现在,您已经看到了代码,红色警告标志应该上升您正在创建一组GDI+对象(画笔、笔、区域等),但未能
处理它们中的任何一个几乎所有这些代码都应该使用
语句包装在
中。那只是草率的编码

做所有这些工作都要付出一些代价。当计算机被迫花这么多时间渲染控件时,其他方面就会落后。你会看到一个闪烁,因为它的应变,以跟上调整大小。它与任何其他使计算机过载的操作(比如计算pi值)没有什么不同,当您使用像这里一样多的自定义绘制控件时,这样做非常容易。在Win32中,透明度很难实现,许多自定义3D绘制也是如此。它让用户觉得UI看起来和感觉都很笨拙。还有另一个原因,我不明白为什么要匆忙离开本机控件

您实际上只有三种选择:

  • 处理闪烁。(我同意,这不是一个好的选择。)
  • 使用不同的控件,如标准的内置控件。当然,它们可能没有奇特的渐变效果,但如果用户自定义了他们的Windows主题,那么在大多数情况下,这种效果都会被破坏。在深灰色背景下阅读黑色文本也相当困难
  • 更改自定义控件中的绘制代码以减少工作量。你也许可以通过一些简单的“优化”而不需要任何视觉效果,但我怀疑这是不可能的。这是速度和吸引眼球之间的折衷。什么都不做总是更快

  • 虽然挂接ResizeBegin和ResizeEnd是正确的想法,但与其隐藏主面板的可见性,不如将任何调整大小的计算延迟到ResizeEnd。在这种情况下,您甚至不需要挂接ResizeBegin或Resize,所有的逻辑都进入ResizeEnd


    我这样说有两个原因。第一,即使面板是隐藏的,调整大小的操作可能仍然是昂贵的,因此除非调整大小的计算被延迟,否则表单将感觉不到应有的响应。第二,在调整大小时隐藏窗格的内容可能会让用户感到不安。

    我使用此代码成功地消除了表单调整大小时的闪烁。谢谢

    VB.NET

    Public Class Form1
    
    Public Sub New()
        Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.AllPaintingInWmPaint Or ControlStyles.SupportsTransparentBackColor, True)
    End Sub
    
    Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        Me.Update()
    End Sub
    
    End Class
    
    C#


    要在调整win窗体大小时消除闪烁,请在调整大小时暂停布局。重写表单resizebegin/resizeend方法,如下所示

    protected override void OnResizeBegin(EventArgs e) {
        SuspendLayout();
        base.OnResizeBegin(e);
    }
    protected override void OnResizeEnd(EventArgs e) {
        ResumeLayout();
        base.OnResizeEnd(e);
    }
    

    这将使控件保持不变(在调整大小之前),并在调整大小操作完成时强制重新绘制。

    因此我遇到了同样的问题-我的透明背景控件重新绘制了34次,对我有效的是:

    在我包含控件的窗体上

    protected override void OnResize(EventArgs e)
        {
            myControl.Visible = false;
            base.OnResize(e);
            myControl.Visible = true;
        }
    
    在对照组中也是如此:

    protected override void OnResize(EventArgs e)
        {
            this.Visible = false;
            base.OnResize(e);
            this.Visible = true;
        }
    

    这将重新绘制的数量减少到4,有效地消除了控件调整大小时的任何闪烁。

    我也有同样的问题

    这可能是因为您使用的是圆角。当我将CornerRadius属性设置为0时,闪烁消失了

    到目前为止,我只找到了以下解决方法。不是最好的,但它能阻止闪烁

    private void Form_ResizeBegin(object sender, EventArgs e)
    {
      rectangleShape.CornerRadius = 0;
    }
    
    private void Form_ResizeEnd(object sender, EventArgs e)
    {
      rectangleShape.CornerRadius = 15;
    }
    

    我也有类似的问题。我的整个表单正在缓慢调整大小,控件以一种丑陋的方式绘制它们。这对我有帮助:

    //I Added This To The Designer File, You Can Still Change The WindowState In Designer View If You Want. This Helped Me Though.
    this.WindowState = FormWindowState.Maximized;
    
    在Resize事件中,将此代码添加到开头

    this.Refresh();
    

    如果我没有落选,我会投票结束这个问题,作为这个问题的重复。所以这里是免费的。@Cody Gray-我不同意!问题可能类似,但您发送的链接下提供的答案完全错误/不好,因为它会导致很多副作用。@HABJAN:您能告诉我一些副作用吗?@Cody Gray:Tab control有时会失去主题。(其他一些控件也是如此)Windows Med
    this.Refresh();