86

I've been fighting with this for a while, and have found that a number of other people struggle with the TableLayoutPanel (.net 2.0 Winforms) as well.

Problem

I am attempting to take a 'blank' tablelayoutpanel, which has 10 columns defined, then at runtime programmatically add rows of controls (i.e. one control per cell).

One might have thought that it should be as simple as

myTableLayoutPanel.Controls.Add(myControl, 0 /* Column Index */, 0 /* Row index */);

But that (for me) doesn't add the rows. So maybe adding in a row style

myTableLayoutPanel.RowStyles.Clear();
myTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));

But that doesn't work either. I've dug around and found out that the myTableLayoutPanel.RowCount usage changes from design time to run time, hence doing myTableLayoutPanel.RowCount++; doesn't actually add another row, not even before/after adding a RowStyle entry for it!

Another related issue I am encountering is that the controls will be added to the display, but they all simply get rendered at point 0,0 of the TableLayoutPanel, additionally they are not even constrained to be within the Cell bounds that they are supposed to be displayed within (i.e. with Dock = DockStyle.Fill they still appear way too large/small).

Does someone have a working example of adding rows & controls at runtime?

4

8 回答 8

74

我上周刚做了这个。将设置GrowStyle为或,然后您的代码应该可以工作:TableLayoutPanelAddRowsAddColumns

// Adds "myControl" to the first column of each row
myTableLayoutPanel.Controls.Add(myControl1, 0 /* Column Index */, 0 /* Row index */);
myTableLayoutPanel.Controls.Add(myControl2, 0 /* Column Index */, 1 /* Row index */);
myTableLayoutPanel.Controls.Add(myControl3, 0 /* Column Index */, 2 /* Row index */);

这是一些看起来与您正在做的类似的工作代码:

    private Int32 tlpRowCount = 0;

    private void BindAddress()
    {
        Addlabel(Addresses.Street);
        if (!String.IsNullOrEmpty(Addresses.Street2))
        {
            Addlabel(Addresses.Street2);
        }
        Addlabel(Addresses.CityStateZip);
        if (!String.IsNullOrEmpty(Account.Country))
        {
            Addlabel(Address.Country);
        }
        Addlabel(String.Empty); // Notice the empty label...
    }

    private void Addlabel(String text)
    {            
        label = new Label();
        label.Dock = DockStyle.Fill;
        label.Text = text;
        label.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
        tlpAddress.Controls.Add(label, 1, tlpRowCount);
        tlpRowCount++;
    }

TableLayoutPanel总是给我适合的大小。在上面的示例中,我提交的地址卡可能会根据具有地址行 2 的帐户或国家/地区而增长或缩小。因为表格布局面板的最后一行或最后一列会拉伸,所以我将空标签扔在那里以强制一个新的空行,然后一切都很好地排列。

这是设计器代码,因此您可以看到我开始的表格:

        //
        // tlpAddress
        // 
        this.tlpAddress.AutoSize = true;
        this.tlpAddress.BackColor = System.Drawing.Color.Transparent;
        this.tlpAddress.ColumnCount = 2;
        this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 25F));
        this.tlpAddress.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
        this.tlpAddress.Controls.Add(this.pictureBox1, 0, 0);
        this.tlpAddress.Dock = System.Windows.Forms.DockStyle.Fill;
        this.tlpAddress.Location = new System.Drawing.Point(0, 0);
        this.tlpAddress.Name = "tlpAddress";
        this.tlpAddress.Padding = new System.Windows.Forms.Padding(3);
        this.tlpAddress.RowCount = 2;
        this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle());
        this.tlpAddress.RowStyles.Add(new System.Windows.Forms.RowStyle());
        this.tlpAddress.Size = new System.Drawing.Size(220, 95);
        this.tlpAddress.TabIndex = 0;
于 2010-02-02T05:58:06.033 回答
30

这是一个奇怪的设计,但TableLayoutPanel.RowCount属性不反映RowStyles集合的数量,对于ColumnCount属性和ColumnStyles集合也是如此。

我发现我在代码中需要的是在更改RowCount/ColumnCount之后手动更新RowStyles/ ColumnStyles

这是我使用的代码示例:

    /// <summary>
    /// Add a new row to our grid.
    /// </summary>
    /// The row should autosize to match whatever is placed within.
    /// <returns>Index of new row.</returns>
    public int AddAutoSizeRow()
    {
        Panel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
        Panel.RowCount = Panel.RowStyles.Count;
        mCurrentRow = Panel.RowCount - 1;
        return mCurrentRow;
    }

其他想法

  • 我从来没有使用DockStyle.Fill过让控件填充网格中的单元格。我通过设置Anchors控件的属性来做到这一点。

  • 如果您要添加大量控件,请确保您调用SuspendLayoutResumeLayout围绕该过程,否则在添加每个控件后整个表单都会重新加载,因此运行速度会很慢。

于 2010-02-21T21:52:22.243 回答
17

这是我向两列 TableLayoutColumn 添加新行的代码:

private void AddRow(Control label, Control value)
{
    int rowIndex = AddTableRow();
    detailTable.Controls.Add(label, LabelColumnIndex, rowIndex);
    if (value != null)
    {
        detailTable.Controls.Add(value, ValueColumnIndex, rowIndex);
    }
}

private int AddTableRow()
{
    int index = detailTable.RowCount++;
    RowStyle style = new RowStyle(SizeType.AutoSize);
    detailTable.RowStyles.Add(style);
    return index;
}

标签控件位于左列,值控件位于右列。这些控件通常是 Label 类型,并且其 AutoSize 属性设置为 true。

我认为这并不重要,但作为参考,这里是设置 detailTable 的设计器代码:

this.detailTable.ColumnCount = 2;
this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.detailTable.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.detailTable.Dock = System.Windows.Forms.DockStyle.Fill;
this.detailTable.Location = new System.Drawing.Point(0, 0);
this.detailTable.Name = "detailTable";
this.detailTable.RowCount = 1;
this.detailTable.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.detailTable.Size = new System.Drawing.Size(266, 436);
this.detailTable.TabIndex = 0;

这一切都很好。您应该知道,使用 Controls 属性从 TableLayoutPanel 动态处理控件似乎存在一些问题(至少在某些版本的框架中)。如果您需要删除控件,我建议处置整个 TableLayoutPanel 并创建一个新的。

于 2010-02-18T16:02:45.203 回答
7

在表单中创建一个包含两列的表格布局面板并将其命名tlpFields

然后,只需将新控件添加到表格布局面板(在本例中,我在 column-1 中添加了 5 个标签,在 column-2 中添加了 5 个文本框)。

tlpFields.RowStyles.Clear();  //first you must clear rowStyles

for (int ii = 0; ii < 5; ii++)
{
    Label l1= new Label();
    TextBox t1 = new TextBox();

    l1.Text = "field : ";

    tlpFields.Controls.Add(l1, 0, ii);  // add label in column0
    tlpFields.Controls.Add(t1, 1, ii);  // add textbox in column1

    tlpFields.RowStyles.Add(new RowStyle(SizeType.Absolute,30)); // 30 is the rows space
}

最后,运行代码。

于 2012-10-02T08:52:55.963 回答
4

我只是查看了我的代码。在一个应用程序中,我只添加了控件,但没有指定索引,完成后,我只是循环遍历行样式并将大小类型设置为 AutoSize。因此,仅添加它们而不指定索引似乎会按预期添加行(前提是 GrowStyle 设置为 AddRows)。

在另一个应用程序中,我清除控件并将 RowCount 属性设置为所需的值。这不会添加 RowStyles。然后我添加我的控件,这次指定索引,并添加一个新的 RowStyle ( RowStyles.Add(new RowStyle(...)),这也有效。

因此,选择其中一种方法,它们都有效。我记得表格布局面板给我带来的头痛。

于 2009-07-17T12:18:44.150 回答
0

这非常适合在 TableLayoutPanel 中添加行和控件。

在设计页面中定义一个包含 3 列的空白 Tablelayoutpanel

    Dim TableLayoutPanel3 As New TableLayoutPanel()

    TableLayoutPanel3.Name = "TableLayoutPanel3"

    TableLayoutPanel3.Location = New System.Drawing.Point(32, 287)

    TableLayoutPanel3.AutoSize = True

    TableLayoutPanel3.Size = New System.Drawing.Size(620, 20)

    TableLayoutPanel3.ColumnCount = 3

    TableLayoutPanel3.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single

    TableLayoutPanel3.BackColor = System.Drawing.Color.Transparent

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 26.34146!))

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 73.65854!))

    TableLayoutPanel3.ColumnStyles.Add(New ColumnStyle(SizeType.Absolute, 85.0!))

    Controls.Add(TableLayoutPanel3)

创建一个按钮 btnAddRow 以在每次单击时添加行

     Private Sub btnAddRow_Click(sender As System.Object, e As System.EventArgs) Handles btnAddRow.Click

          TableLayoutPanel3.GrowStyle = TableLayoutPanelGrowStyle.AddRows

          TableLayoutPanel3.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))

          TableLayoutPanel3.SuspendLayout()

          TableLayoutPanel3.RowCount += 1

          Dim tb1 As New TextBox()

          Dim tb2 As New TextBox()

          Dim tb3 As New TextBox()

          TableLayoutPanel3.Controls.Add(tb1 , 0, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.Controls.Add(tb2, 1, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.Controls.Add(tb3, 2, TableLayoutPanel3.RowCount - 1)

          TableLayoutPanel3.ResumeLayout()

          tb1.Focus()

 End Sub
于 2014-09-30T08:30:05.670 回答
0

我刚刚遇到了一个相关的问题(这就是我找到这个线程的方式),我动态添加的行和列样式没有生效。我通常将 SuspendLayout()/ResumeLayout() 视为优化,但在这种情况下,将我的代码包装在其中会使行和列的行为正确。

于 2015-01-22T21:32:27.087 回答
-2
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim dt As New DataTable
        Dim dc As DataColumn
        dc = New DataColumn("Question", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)

        dc = New DataColumn("Ans1", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans2", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans3", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("Ans4", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)
        dc = New DataColumn("AnsType", System.Type.GetType("System.String"))
        dt.Columns.Add(dc)


        Dim Dr As DataRow
        Dr = dt.NewRow
        Dr("Question") = "What is Your Name"
        Dr("Ans1") = "Ravi"
        Dr("Ans2") = "Mohan"
        Dr("Ans3") = "Sohan"
        Dr("Ans4") = "Gopal"
        Dr("AnsType") = "Multi"
        dt.Rows.Add(Dr)

        Dr = dt.NewRow
        Dr("Question") = "What is your father Name"
        Dr("Ans1") = "Ravi22"
        Dr("Ans2") = "Mohan2"
        Dr("Ans3") = "Sohan2"
        Dr("Ans4") = "Gopal2"
        Dr("AnsType") = "Multi"
        dt.Rows.Add(Dr)
        Panel1.GrowStyle = TableLayoutPanelGrowStyle.AddRows
        Panel1.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
        Panel1.BackColor = Color.Azure
        Panel1.RowStyles.Insert(0, New RowStyle(SizeType.Absolute, 50))
        Dim i As Integer = 0

        For Each dri As DataRow In dt.Rows



            Dim lab As New Label()
            lab.Text = dri("Question")
            lab.AutoSize = True

            Panel1.Controls.Add(lab, 0, i)


            Dim Ans1 As CheckBox
            Ans1 = New CheckBox()
            Ans1.Text = dri("Ans1")
            Panel1.Controls.Add(Ans1, 1, i)

            Dim Ans2 As RadioButton
            Ans2 = New RadioButton()
            Ans2.Text = dri("Ans2")
            Panel1.Controls.Add(Ans2, 2, i)
            i = i + 1

            'Panel1.Controls.Add(Pan)
        Next
于 2012-03-20T23:14:39.167 回答