Get rid of blinking when adding controls dynamically to FlowLayoutpanel, triggered by timer

2k views Asked by At

I'm trying to make a custom control, to show some data from a SQL source. The data should change in a method, which is triggered by a Timer control.

Let say, if I append all my needed data in stringbuffer and then I show this in long label is working. Every time label is repainted, there is no blinking.

But, if I want make more fancy look, I found only way to put controls in FLowLayoutPanel and build whole structure. Ok, it works, but every time the controls are drawn, I need to dispose them. If not, controls being added to infinity, and buffer overload.

But If I dispose() or clear() them, there is blinking every time controls are redrawn.

Is there a way to get rid of this blinking? Or maybe some other way to do my work?

My code:

void timer_Tick(object sender, EventArgs e)
    {
        try
        {            
            GetMapData();
        }
        catch (Exception ex)
        {

        }
    }

  private void GetMapData()
  {
       DataSet ds = MapStatistics.GetMapData(top, bottom, left, right, idUnit, idCustomerTmp);
       DataTable activDriversForZones = ds.Tables["ActivDriversForZone"];
       DataTable zones zones = ds.Tables["Zones"];

        if (zones != null || zones.Rows.Count > 0)
        {
            ClearflpPanel(flpTest2);

            zonesDriverCount = 0;
            foreach (DataRow rowZones in zones.Rows)
            {

                string idZone = Convert.ToString(rowZones["id_zone"]);
                string title = Convert.ToString(rowZones["title"]);

                StringBuilder zoneDriver = new StringBuilder();

                Label labelRowZone = new Label();
                labelRowZone.Width = 400;
                labelRowZone.AutoSize = true;
                labelRowZone.Font = new System.Drawing.Font("Arial", 10, FontStyle.Bold);
                labelRowZone.Text = (title + ": ");

                flpTest2.Controls.Add(labelRowZone);

                Label labelRowDriver = new Label();
                foreach (DataRow rowDriver in activDriversForZones.Rows)
                {
                    string idUnit = Convert.ToString(rowDriver["id_unit"]);
                    string imsi = Convert.ToString(rowDriver["imsi"]);
                    string zoneIn = Convert.ToString(rowDriver["zone_in"]);

                    if (idZone == zoneIn)
                    {
                        zonesDriverCount++;
                        zoneDriver.Append(imsi + "/" + idUnit + ", ");
                        labelRowDriver.Text = (zoneDriver.ToString());
                    }

                    flpTest2.Controls.Add(labelRowDriver);
                }

            }
        } 
   }

   public void ClearflpPanel(FlowLayoutPanel flp)
    {
        zonesDriverCount = 0;
        List<Control> listControls = flp.Controls.Cast<Control>().ToList();

        foreach (Control control in listControls)
        {
            flpTest2.Controls.Clear();
            //flpTest2.Dispose();
        }
    }
2

There are 2 answers

0
Vajura On

Create a custom flowLayoutPanel class and add this in its constructor

public class CustomFLP: FlowLayoutPanel 
{
    public CustomFLP() : base()
    {
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.UpdateStyles();
    }
}

Then do everything the same way you are doing now except you create your flowlayout panel with CustomFLP instead of FlowLayoutPanel.

This adds a double buffer to your control, might not work with a lot of updates.

0
Jian On

I find combining Vajura's method and wrap the update with SuspendLayout() / ResumeLayout() will completely remove the flickering.

// Declaration
CustomFLP m_doubleBufferFlowLayoutPanel;

void UpdatePanel()
{
    m_doubleBufferFlowLayoutPanel.SuspendLayout();

    // update the flow layout panel here
    ...

    m_doubleBufferFlowLayoutPanel.ResumeLayout();
}