简体   繁体   中英

Fast way to add Controls to a TableLayoutPanel

I have to add a lot of Control objects to a TableLayoutPanel dynamically, what takes a significant amount of time. I also need to be able to access the controls via row- and column-index of the TableLayoutPanel and vice versa.

TableLayoutPanel.Controls has (as far as I know) 3 ways to add Control objects:

  • .Add(Control) - inherited, position is -1,-1 with .GetCellPosition(Control)
  • .Add(Control, column, row) - position and indexes are correct, but maybe a bit slow?
  • .AddRange (Control[]) - inherited, faster, shown position is correct (every cell is filled, if necessary columnspans are set afterwards), but position is -1,-1 with .GetCellPosition(Control)

Is there a way to combine the advantages of .Add(Control, column, row and .AddRange(Control[]) , ie to add a lot of Control objects fast to a TableLayoutPanel while still being able to get the position of a Control programmatically?


EDIT to include some information from the comments:

  • There are up to 1000 controls added
  • I already use SuspendLayout() and ResumeLayout()
  • The TableLayoutPanel takes about 2 seconds to load. According to the profiler roughly 50% of the time is spent with adding Controls, 20% with ResumeLayout()

EDIT: MCVE
My original code is more complex, but this is an example of a TableLayoutPanel where adding the controls takes most of the time spent (2/3). I am searching for a way to speed this up.

public class FormTLPTest : Form
{
    public FormTLPTest()
    {
        Height = 800;
        Width = 800;

        TableLayoutPanel tlp = new TableLayoutPanel();
        tlp.Dock = DockStyle.Fill;
        tlp.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single;
        tlp.AutoScroll = true;

        Controls.Add(tlp);

        tlp.ColumnCount = 7;
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100.0F));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 80));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 100));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 30));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 70));
        tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 20));

        tlp.SuspendLayout();

        for (int i = 0; i<700; i++)
        {
            Button btn1 = new Button();
            Label lb2 = new Label();
            Label lb3 = new Label();
            Label lb4 = new Label();
            TextBox tb5 = new TextBox();
            Button btn6 = new Button();
            Button btn7 = new Button();

            foreach (Control c in new Control[] { btn1, lb2, lb3, lb4, tb5, btn6, btn7})
            {
                c.Margin = new Padding();
                c.Dock = DockStyle.Fill;
                c.BackColor = Color.White;
            }

            btn1.FlatStyle = FlatStyle.Flat;
            btn6.FlatStyle = FlatStyle.Flat;
            btn7.FlatStyle = FlatStyle.Flat;

            btn1.Text = "1";
            lb2.Text = "Some longer Text - it contains information. Don't know what I should write to fill the space";
            lb3.Text = "Short Text";
            lb4.Text = "Short Text";
            tb5.Text = "5";
            btn6.Text = "Button";
            btn7.Text = "+";

            tlp.Controls.Add(btn1, 0, i);
            tlp.Controls.Add(lb2, 1, i);
            tlp.Controls.Add(lb3, 2, i);
            tlp.Controls.Add(lb4, 3, i);
            tlp.Controls.Add(tb5, 4, i);
            tlp.Controls.Add(btn6, 5, i);
            tlp.Controls.Add(btn7,6, i);
        }

        tlp.ResumeLayout();
    }
}

Looking at the Reference Source , you can see that Control.ControlCollection.AddRange method is nothing more than a Add loop enclosed in SuspendLayout / ResumeLayout . Since your code is also enclosed with such calls, there should not be a difference in the performance.

TableLayoutPanel does two additional calls - SetRow and SetColumn , so my first thought was that they are the slow parts. However, looking at the the source code (and measuring the time with or w/o those calls), when the layout engine is suspended, their affect on the performance are negligible.

I did some additional tests with your mcve by not using TableLayoutPanel at all and just adding controls to the form itself. The conclusion is - you just have too many controls. mcve is creating 4900 controls. This is too much for WinForms (and Windows in general). After running it, my Windows almost died.

So, the add control performance cannot be improved. But that should not be your main concern. Consider switching to DataGridView or some third party data repeater control which support a lot more number of rows w/o creating significant number of controls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM