面板为什么在移除它及其孩子时会闪烁?

时间:2015-06-28 23:36:57

标签: c# .net winforms

我有一个包含自定义控件的表单UserControls。其中一个控件由其他控件组成:TableLayoutPanelPictureBox(它位于另一个UserControl内),Label。在视觉上,它们以下列方式描述:

Visual description

正如我们在图片中看到的那样,红色矩形是UserControl,橙色矩形是TableLayoutPanel,黄色和绿色椅子是由{{UserControl组成的其他PictureBox控件1}}和Label

椅子(黄色和绿色)是动态绘制的。例如,绘制黄色椅子:

    private void DibujarSillasEconomicas()
    {
        Silla[] cheapChairs = m_avion.GetCheapChairs();
        Silla silla;
        byte fila_silla = 0;
        byte col_silla = 0;
        ControlVisualChair ctlSillaGrafica;

        for(int num_silla = 0; num_silla < cheapChairs.Length; ++num_silla)
        {
            silla = cheapChairs[num_silla];
            ctlSillaGrafica = new ControlSillaGrafica(silla);
            ctlSillaGrafica.Dock = DockStyle.Fill;
            ctlSillaGrafica.BackColor = Color.Black;

            if (num_silla > 0 & num_silla % 6 == 0)
            {
                ++fila_silla;
                col_silla = 0;
            }

            tplSillasEconomicas.Controls.Add(ctlSillaGrafica, col_silla == 3? ++col_silla : col_silla, fila_silla);

            ++col_silla;
        }
    }

正确绘制这些椅子和黄色椅子。当我想要登记乘客时出现问题:

Adding a passenger

请注意,当我添加乘客时,控件会闪烁。在代码中,这是我在添加乘客时所做的事情:

this.Controls.Remove(ctlAvion); // Removes the actual UserControl (red rectangle)
ctlAvion = new ControlAvion(m_avion); // Creates a new one
ctlAvion.Location = new Point(2, 13);
ctlAvion.Size = new Size(597, 475);
this.Controls.Add(ctlAvion); // Adds the new UserControl to the main controls (a Form).

我怎样才能避免这种眨眼效应?

我尝试过以下UserControls方法:

ctlAvion.Invalidate();
ctlAvion.Update();
ctlAvion.Refresh();

但它们不起作用!

提前感谢您的帮助!

编辑:

@Idle_Mind给出的答案特定于我的问题,它解决了我重新绘制/绘制我设计的自定义控件的问题。

4 个答案:

答案 0 :(得分:3)

在对面板控件进行任何修改之前以及之后调用SuspendLayout()之前,请尝试使用ResumeLayout()

还可以对控件进行双缓冲,例如,对于面板定义此类并使用它而不是面板

public class PanelEx : Panel
{
    public PanelEx()
    {
        SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        UpdateStyles();
    }
}

答案 1 :(得分:2)

使用WM_SETREDRAW关闭更新,更新您的UI,然后重新打开它们并刷新表单:

    // ... at Form level ...
    private const int WM_SETREDRAW = 11; 

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);

    // ... some method ...

        SendMessage(this.Handle, WM_SETREDRAW, false, 0); // turn updates off

        this.Controls.Remove(ctlAvion); // Removes the actual UserControl (red rectangle)
        ctlAvion = new ControlAvion(m_avion); // Creates a new one
        ctlAvion.Location = new Point(2, 13);
        ctlAvion.Size = new Size(597, 475);
        this.Controls.Add(ctlAvion); // Adds the new UserControl to the main controls (a Form).

        SendMessage(this.Handle, WM_SETREDRAW, true, 0); // turn updates back on
        this.Invalidate();
        this.Refresh();

答案 2 :(得分:0)

应用程序必须重新创建整个UserControl,因此您可以在按下“接受”按钮时隐藏控件,然后修改控件,然后再次显示控件。 在此期间,当您的UserControl被隐藏时,您可以显示类似加载屏幕的内容。

答案 3 :(得分:0)

闪烁来自OnPaintBackground事件,它在绘制前景之前绘制背景,它具有闪烁效果。 您可以覆盖OnPaintBackground而不执行任何操作。并使其成为DoubleBuffered。

public class FlickerFreePanel : System.Windows.Forms.Panel
{
    public FlickerFreePanel()
    {
        this.DoubleBuffered = true;
    }

    protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs e)
    {
        if (this.DesignMode)
        {
            base.OnPaintBackground(e);
        }

        // Do nothing
    }
}