快速向TableLayoutPanel添加控件的方法

3
我需要动态地向TableLayoutPanel添加许多Control对象,这需要相当长的时间。我还需要能够通过TableLayoutPanel的行列索引来访问控件,反之亦然。
据我所知,TableLayoutPanel.Controls有三种方法来添加Control对象:
- .Add(Control) - 继承而来,位置为-1,-1,使用.GetCellPosition(Control)获取位置。 - .Add(Control, column, row) - 位置和索引正确,但可能有点慢? - .AddRange (Control[]) - 继承而来,速度更快,显示位置正确(每个单元格都被填充,必要时设置跨列),但使用.GetCellPosition(Control)获取位置时为-1,-1。
有没有一种方法可以结合 .Add(Control, column, row).AddRange(Control[]) 的优点,即快速向 TableLayoutPanel 添加大量 Control 对象,同时仍然能够以编程方式获取 Control 的位置?

编辑 包含一些来自评论的信息:

  • 最多添加了1000个控件
  • 我已经使用了SuspendLayout()ResumeLayout()
  • TableLayoutPanel需要大约2秒钟才能加载。 根据分析器,大约50%的时间用于添加控件,20%用于ResumeLayout()

编辑:MCVE
我的原始代码更加复杂,但这是一个TableLayoutPanel的例子,其中添加控件占用了大部分时间(2/3)。我正在寻找一种加速此过程的方法。

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

3
在添加之前,您是否暂停了布局?通常重绘是问题所在。 - Patrick Hofman
你是否使用了性能分析器来检查性能损失的位置?我已经进行了大量的工作,试图优化TLP,通常不是面板的问题。 - Patrick Hofman
你也暂停了面板吗? - Patrick Hofman
2
最好先构造一个 mcve 并展示出来。这样很容易看到问题并感受它,或者简单地说“没问题,你必须接受它”,或者提供另一种设计解决方案。你提到了滚动。我不明白滚动和添加有什么关系(除非你是动态添加的?)。 - Sinatr
1
如果您查看参考源,您会发现AddRange只是一个用Suspend/ResumeLayout包围的Add循环。 - Ivan Stoev
显示剩余4条评论
1个回答

5
查看参考源代码,您可以看到Control.ControlCollection.AddRange方法只是一个在SuspendLayout/ResumeLayout中封装的Add循环。由于您的代码也包含这些调用,因此性能不应有差异。 TableLayoutPanel还执行了两个额外的调用-SetRowSetColumn,因此我的第一个想法是它们是慢的部分。然而,查看源代码(并测量带或不带这些调用的时间),当布局引擎被挂起时,它们对性能的影响微不足道。
我使用您的mcve进行了一些额外的测试,完全不使用TableLayoutPanel,只是将控件添加到表单本身。结论是-您有太多控件。 mcve创建了4900个控件。这对WinForms(以及Windows总体)来说太多了。运行它后,我的Windows几乎崩溃了。
因此,添加控件的性能无法提高。但这不应该是您的主要关注点。考虑切换到DataGridView或一些第三方数据重复器控件,它们支持更多的行数而不需要创建大量控件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接