2

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.

InfZero
  • 2,944
  • 4
  • 24
  • 36
  • 2
    Your UI is a bit like that plane, it needs an 8 mile runway to get off the ground. [Try this](http://stackoverflow.com/a/3718648/17034) for a quick fix. – Hans Passant Jun 29 '15 at 02:45
  • This maybe what you are looking for: http://stackoverflow.com/questions/487661/how-do-i-suspend-painting-for-a-control-and-its-children – Nam Bình Jun 29 '15 at 09:45
  • @HansPassant, do you know how I can profile/benchmark the "weight" of my UI. – InfZero Jun 29 '15 at 20:43

4 Answers4

3

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();
    }
}
Hamid Pourjam
  • 20,441
  • 9
  • 58
  • 74
  • I have followed what you have recommended me, but it does solve the blinking effect. I have put `ctlAvion.SuspendLayout()` and `ctlAvion.ResumeLayout()` when re-create the `UserControl`. Thanks. – InfZero Jun 28 '15 at 23:54
  • Correct: "...but it does NOT solve the blinking effect.". Sorry for that typo! – InfZero Jun 29 '15 at 00:41
2

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();
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Thanks @Idle_Mind. Your clear answer solved my problem with re-painting/drawing the custom controls. – InfZero Jun 29 '15 at 16:07
0

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.

DerAtrox
  • 183
  • 10
0

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
    }
}
Yohanes Nurcahyo
  • 601
  • 8
  • 19