Winforms TableLayoutPanel如何通过编程添加行

86

我已经为此苦战了一段时间,并发现许多其他人也与TableLayoutPanel (.net 2.0 Winforms) 难以应付。

问题

我试图在运行时以编程方式添加控件行(即每个单元格一个控件)到一个“空白的”tablelayoutpanel中,该tablelayoutpanel定义了10列。

你可能认为这应该很简单,只需要:

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

但是对我来说,这样做并没有添加行。因此,也许需要添加一种行样式。

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

但是这并不奏效。我查了一下发现,myTableLayoutPanel.RowCount 的使用从设计时到运行时有所变化,因此执行 myTableLayoutPanel.RowCount++; 实际上并没有添加另一行,即使在为其添加 RowStyle 条目之前/之后也不行!

我遇到的另一个相关问题是,控件将被添加到显示中,但它们都只在 TableLayoutPanel 的 0,0 点处呈现,此外它们甚至没有被限制在它们应该在其中显示的单元格范围内(即使使用 Dock = DockStyle.Fill 它们仍然显得太大或太小)。

有人有在运行时添加行和控件的工作示例吗?


添加 RowStyle 实际上会增加 RowStyles.Count()。 - Ed_
8个回答

74

我上周刚做了这件事。将TableLayoutPanel上的GrowStyle设置为AddRowsAddColumns,然后你的代码应该就能正常工作:

// 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总是让我很难掌控大小。在我的示例中,我正在填写一个地址卡片,它可能因为账户有第二行地址或者国家而增长或缩小。由于表格布局面板的最后一行或列会被拉伸,所以我在那里放了一个空标签来强制创建新的空行,这样所有内容都可以很好地对齐。

这是设计师代码,您可以看到我开始使用的表格:

        //
        // 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;

2
感谢提供空白占位行的想法!解决了我的尺寸问题。 - JNadal

31

这是一种奇怪的设计,但是 TableLayoutPanel.RowCount 属性并不反映 RowStyles 集合的数量,ColumnCount 属性也是如此,同样适用于 ColumnStyles 集合。

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

以下是我使用过的代码示例:

    /// <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,否则在每个控件添加后整个窗体都会重新布局,导致运行缓慢。


2
如果有用的话,在我的情况下,当窗体加载时我必须调用 *tableLayoutPanel1.ColumnStyles.Clear();*。 - John

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

这些控件通常是类型,其AutoSize属性设置为true。

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进行处理并创建一个新的。


这非常有帮助。我发现DockStyle.Fill属性是必不可少的。而且,计数方面出错是令人惊讶的容易!此外,请注意使用样式设置的列和行大小。我发现当RowStyle设置为AutoSize时,一些无意中的TextAlign设置变化(在顶部、中间和底部之间)会使表格以某种奇怪的方式生成额外的行,但实际上并非如此。一旦你弄清楚了,这个东西就相当好用,但要到达那里的过程很痛苦! - Jan Hettich

7
在您的表单中创建一个有两列的表格布局面板,将其命名为tlpFields
然后,只需向表格布局面板添加新控件(在本例中,我在第一列添加了5个标签,在第二列添加了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
}

最后,运行代码。

你是如何访问tlpfields的?我已经创建了TableLayoutPanel,它的名称是tabkelayout,但我无法访问它。 - Muneem Habib
@MuneemHabib 前往tabkelayout属性,将Modifiers从private改为public。 - RookieCoder

4

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

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

因此,请选择其中一种方法,它们都有效。我记得TableLayoutPanel曾经让我头痛不已。


我会试一下这些,看看它是否表现良好! - Ash

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

0

我刚遇到了一个相关的问题(这也是我找到这个线程的原因),我的动态添加的行和列样式没有生效。通常情况下,我认为SuspendLayout()/ResumeLayout()是优化的一种方式,但在这种情况下,将我的代码包裹在它们中间使得行和列表现正常。


-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

这个问题是关于TableLayoutPanel的,而这篇文章是关于DataTable的。这篇文章只有代码,没有任何描述其目的的文字。代码中也没有注释。因此,评分为-1。 - Nick Alexeev

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