Winforms TableLayoutPanel以编程方式添加行

我一直在争取一段时间,并发现许多其他人也与TableLayoutPanel(.net 2.0 Winforms)的斗争。

问题

我试图采取一个'空白'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用法从devise时间改变到运行时间,因此做myTableLayoutPanel.RowCount++; 实际上并没有添加其他行,甚至在为它添加RowStyle条目之前/之后!

我遇到的另一个相关的问题是控件将被添加到显示,但他们都只是简单地在TableLayoutPanel的0,0点呈现,另外他们甚至没有被限制在它们应该是Cell的边界内显示在内(即与Dock = DockStyle.Fill他们仍然显得太大/小)。

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

上周我刚刚做了这个。 将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总是给我适合的大小。 在我上面的例子中,我正在申请一个地址卡,这个地址卡可能会随着地址线2或者国家的账号而增长或者缩小。 因为表格布局面板的最后一行或列将伸展,所以我将空标签放在那里强制一个新的空行,然后一切都很好地排列起来。

这里是devise器的代码,所以你可以看到我开始的表格:

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

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

我发现在代码中需要的是在对RowStyles / ColumnStyles进行更改后手动更新RowStyles / 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 ,否则在添加每个控件后,整个表单将被closures,所以会慢。

这里是我添加一个新的行到两列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; } 

标签控件进入左列,值控件进入右列。 控件通常是Labeltypes的,并将其AutoSize属性设置为true。

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

 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属性(至less在某些版本的框架中)dynamic地从TableLayoutPanel中configuration控件似乎存在一些问题。 如果您需要删除控件,我build议处理整个TableLayoutPanel并创build一个新的。

在窗体中创build一个包含两列的表格布局面板,并将其命名为tlpFields

然后,只需将新控件添加到表格布局面板(在这种情况下,我在列-1中添加了5个标签,在列-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 } 

最后,运行代码。

我只是看着我的代码。 在一个应用程序中,我只是添加控件,但没有指定索引,完成后,我只是遍历行样式并将大小types设置为AutoSize。 所以只是添加它们而不指定索引似乎是按照预期添加行(假设GrowStyle设置为AddRows)。

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

所以,select这些方法之一,他们都工作。 我记得桌面布局面板给我带来的麻烦。

 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中添加行和控件。

在devise页面中定义一个带有3列的空白Tablelayout面板

  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) 

创build一个buttonbtnAddRow添加行在每次点击

  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 

我刚刚有一个相关的问题(这是我如何find这个线程),我dynamic添加的行和列样式不起作用。 我通常认为SuspendLayout()/ ResumeLayout()作为优化,但在这种情况下,我的代码包装在其中,使行和列行为正确。