InfZero
InfZero

Reputation: 3045

Why a Panel blinks while removing it and its childs?

I have a form with a custom controls, UserControls. One of these controls is composed with other controls: TableLayoutPanel, PictureBox (it is inside of another UserControl), Label. Visually they are depicted in the following way:

Visual description

As we can see in the image, the red rectangle is a UserControl, the orange rectangles are TableLayoutPanel, the yellow and green chairs are other UserControl controls composed by a PictureBox and a Label.

The chairs (yellow and green ones) are draw dynamically. For example to draw the yellow chairs:

    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;
        }
    }

These chairs and the yellow ones are drawn correctly. The problem appears when I want to register a passenger:

Adding a passenger

Note that when I add a passenger the controls blink. In code this what I do when I finish 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).

How I can avoid this blink effect when?

I have tried the following UserControls methods:

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

but they does not work!

Thanks in advance for your help!

EDIT:

The answer given by @Idle_Mind is specific to my problem and it solved my problem with re-painting/drawing the custom controls I have designed.

Upvotes: 2

Views: 195

Answers (4)

Yohanes Nurcahyo
Yohanes Nurcahyo

Reputation: 621

The flickering come from OnPaintBackground event that paints the background before paint the foreground, it has the flickering effect. You can override OnPaintBackground and just do nothing. And make it 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
    }
}

Upvotes: 0

Idle_Mind
Idle_Mind

Reputation: 39142

Turn off updates with WM_SETREDRAW, update your UI, then turn them back on and refresh the Form:

    // ... 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();

Upvotes: 2

DerAtrox
DerAtrox

Reputation: 183

The application has to recreate the whole UserControl, so you could hide your control when you press the accept button, then you modify the control and after this you show the control again. During the time, when your UserControl is hidden, you could display something like a loading screen or so.

Upvotes: 0

Hamid Pourjam
Hamid Pourjam

Reputation: 20764

Try using SuspendLayout() before any modification to panel controls and after that call ResumeLayout().

Also make your controls double buffered, for example for a panel define this class and use it instead of panel

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

Upvotes: 3

Related Questions