Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Winforms TableLayoutPanel adding rows programmatically

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?

like image 350
Ash Avatar asked Jul 17 '09 12:07

Ash


2 Answers

I just did this last week. Set the GrowStyle on the TableLayoutPanel to AddRows or AddColumns, then your code should work:

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

Here is some working code that seems similar to what you are doing:

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

The TableLayoutPanel always gives me fits with size. In my example above, I'm filing an address card that might grow or shrink depending on the account having an address line two, or a country. Because the last row, or column, of the table layout panel will stretch, I throw the empty label in there to force a new empty row, then everything lines up nicely.

Here is the designer code so you can see the table I start with:

        //         // 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; 
like image 129
Billy Coover Avatar answered Oct 09 '22 07:10

Billy Coover


It's a weird design, but the TableLayoutPanel.RowCount property doesn't reflect the count of the RowStyles collection, and similarly for the ColumnCount property and the ColumnStyles collection.

What I've found I needed in my code was to manually update RowCount/ColumnCount after making changes to RowStyles/ColumnStyles.

Here's an example of code I've used:

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

Other thoughts

  • I've never used DockStyle.Fill to make a control fill a cell in the Grid; I've done this by setting the Anchors property of the control.

  • If you're adding a lot of controls, make sure you call SuspendLayout and ResumeLayout around the process, else things will run slow as the entire form is relaid after each control is added.

like image 35
Bevan Avatar answered Oct 09 '22 07:10

Bevan