1. Uploaded to WindowsClient.net by  admin on 05-09-2007

TableLayoutPanel

TableLayoutPanel is a panel which lays out its child controls according to rows and columns. Row and column styles, row spanning and column spanning are supported.

Our primary weapon in our auto-layout arsenal is the Table Layout Panel (TLP). TLPs act similar to HTML tables in their ability to regulate space and flow on a form. The TableLayoutPanel has several key sources of information that it uses to determine the size/location of child controls, a collection of child controls to layout (in the Control collection), a number of rows and columns to generate, and a collection of row and column styles to determine the sizing characteristics for each row/column.

So I should use TableLayoutPanel everywhere, right?

 No - TableLayoutPanel is very powerful, but was designed to provide a very specific set of functionality. It is tempting to try to use it in all new Whidbey forms, but this generally leads to sadness and misery, specifically in the form of shoddy UI performance.

 

Here is a quick list of the sorts of UI that benefit most from the use of TLP:

 

Here's a list of types of UI that do not benefit greatly from the use of TLP:

Suggestions

Scenarios for TableLayout

AutoLoc use in dialogs - Push adjacent controls out of the way when localized – using autosized rows/columns will automatically push labels/textboxes that have grown as a result of localization.

Proportionally distribute up space on resize – rather than have the splitter model where only one side grows, as the dialog grows, grow both sides of the dialog equally.  This was not something you could easily do with Anchor layout.

Adding Controls

Controls can be added to the TableLayoutPanel in a free-styled manner via the Add method on the Controls collection. The newly added control will be added in the next available cell, but generally column and row positions are assigned to the child controls:

C#
Edit|Remove
tableLayoutPanel.Controls.Add(button1, 2,3)  
 
 
will add at column = 2, row = 3

Positioning Controls

Additionally the tableLayoutPanel provides several methods to change the position of controls that are already added to the table:

C#
Edit|Remove
tableLayoutPanel.SetCellPosition(new TableLayoutPanelCellPosition(4,2)) 
 
 

 NOTE: Via extender provider on the control itself the SetRow and SetColumn methods can be used.

 To determine where a control was place programmatically use the following: 

  public TableLayoutPanelCellPosition GetPositionFromControl(Control control);||

 

Absolutely position elements within a TableLayoutPanel

The margin property of control can be used to adjust the distance from the edge of the cell.  If you change the anchor to be Top|Left and change the Margin to be (20,3,0,0) the control will be 20 pixels from the left edge and 3 pixels from the top.

Stretching and aligning elements within a TableLayoutPanel

You can use the anchor property of the control to align to a particular side (e.g. Left will stick it to the Left side).  Using opposing anchors, the control can be stretched.  E.g. Anchor=Left|Right will stretch to fill the width.  The Dock property works in a similar manner.

Column and RowStyles

The ColumnStyles and RowStyles collection control the sizing of all the rows and columns.  If these are empty or there are more rows/columns than styles, it is assumed the column/row is "AutoSized". 

 NOTE: Although not strictly required, at design time we attempt to preserve a 1:1 mapping between row and rowstyle along with column and columnstyle. Because these collections in runtime are independent, alteration of one collection can result in sync problems between the two and unexpected results.

Row/Column space distribution

The Row and Column Styles collection are used to determine how to allocate space within the table. Rows and columns are allocated space in a non-autosized TableLayoutPanel in the following order:

  1. Absolutely columns/rows (full space allocated)
  2. AutoSized columns/rows (as much as possible to fit the controls in the column/row)
  3. Percentage columns/rows (distribution of remaining space)

Example I: Percentage styled columns attempt to fill the remaining space.  So a 200px wide table with 20px absolute, an auto sized column and a 100% column would go like this:

  1. col1 ABS: 20 px
  2. col2 AUTO: whatever the preferred size is... say this measures to be 100px
  3. col3 100%: 200 - 20 - 100 = 80px.

Example II: If there are two percentage style columns, the 80 pixels would be divied up between the two columns in proportion to one another - so if we had 20% and 80% it would be:

  1. col1 ABS: 20 px
  2. col2 AUTO: whatever the preferred size is... say this measures to be 100px
  3. col3 20%: (200 - 20 – 100) = 80px remaining space.          80px * .20  = 16px.
  4. col4 80%: (200 - 20 – 100) = 80px remaining space.          80px * .80  = 64px.

Example III: Exactly the same as above but the two percentage style columns are both 75%, the 80 pixels would be split equally between the two normalized columns:

  1. col1 ABS: 20 px
  2. col2 AUTO: whatever the preferred size is... say this measures to be 100px
  3. col3 75% (normalizes to 50%): (200 - 20 – 100) = 80px remaining space.     80px * .50  = 40px.
  4. col4 75% (normalizes to 50%): (200 - 20 – 100) = 80px remaining space.     80px * .50  = 40px.

Example IV: The last column covers the table layout panels underwear. So a 200px wide table with 20px absolute, an auto sized column and a 20px absolute would go like this: 

  1. col1 ABS: 20 px
  2. col2 AUTO: whatever the preferred size is... say this measures to be 100px
  3. col3 ABS: 20 px, not enough pixels so we stretch the last column to be (200 - 20 – 100) = 80px

Generation of Rows and Columns

Whereas the getter for RowCount / ColumnCount returns the number of rows or columns in the table layout panel respectively, the setter is peculiar in that it sets the minimum number of rows or columns to create. This is throttled by the surprisingly well named GrowStyle property that determines how and if rows or columns are added via the AddRows (default), AddColumns or Fixed option.

 

GrowStyle

Rows property

Columns property

Fixed

Specifies the number of rows to create

Specifies the number of columns to create

AddRows

specifies the minimum number of rows to create, more will be created if needed.

Specifies the number of columns to create

AddColumns

specifies the number of rows to create.

Columns property specifies the minimum number of rows to create, more will be created if needed.

Extender-provider properties

Rather than have properties on Cells, the table layout panel proffers properties on the controls within the cells via extender providers. Below is the list of those offered.

CellPosition

public void SetCellPosition(Control control, TableLayoutPanelCellPosition position);

Specifies the where the column and row where a control should be placed. -1, -1 means place at next free position. 

 

Column

public int GetColumn(Control control);

public void SetColumn(Control control, int column);  

Specify the where the column where a control should be placed. -1,  means place at next free position 

  

ColumnSpan

public int GetColumnSpan(Control control);

public void SetColumnSpan(Control control, int value);

Specify how many columns this control should span. (default is 1)

 

Row

public int GetRow(Control control);

public void SetRow(Control control, int row);

Specify the where the row where a control should be placed. -1,  means place at next free position.

 

Example: Maintain equal sizing amongst horizontally-aligned autosizing buttons

Here is the scenario:

 

Simply setting Button.AutoSize=true would cause the buttons to have unequal size, ala:

 

Instead,

  1. place the controls within a TableLayoutPanel
  2. One row and three columns for this example

  1. Set each column to equal percentage column style
  2. Anchor all buttons Left, Right (stretch)
  3. Set TableLayoutPanel AutoSize to true

The buttons now will resize correctly.

Example: Autolayout considerations for textbox button combinations

Every scenario differs a bit, but a TableLayoutPanel can often address this issue. For instance, if you have the following arrangement:

Simple setting the button to AutoSize (assuming the button is anchored Top, Left) would "push" the form bigger (assuming the Form was AutoSize=true), ala:

 

What you really want is for the form to remain its current size and the button to take up space from the textbox. To accomplish this:

  1. Place both in a 2 column, 1 row TableLayoutPanel
  2. Set the Button's column to be AutoSize
  3. Set the TextBox's column to be 100%, and presto, you get: 

 

Example: Layout group boxes with TableLayoutPanel

 

Group boxes tend to have similar behavior to dialogs except that they contain fewer controls. Also, many group boxes will be required to grow vertically with font changes and still stretch with the form. The below example has a TableLayoutPanel inside a group box. The Group Box has its padding set to 0 all around and the TableLayoutPanel has a margin of 9 all around.

 

A single absolute column style in this table layout panel restricts the width of the rest of the contents and allows the font to wrap. Also, this way we can anchor the table layout panel top, left and right so the contents will stretch with the groupbox.

 



 

Example: Non-resizable dialogs

Dialogs with a fixed border are generally the easiest to set up auto-layout for. They should have an overarching TLP with AutoSize set to true and AutoSizeMode set to GrowAndShrink. The Form it is on should be set to AutoSize = true with an AutoSizeMode of GrowAndShrink.

  

  

 

 Resizable Dialogs

 

 













 TextWrapping

What are the the techniques for text wrapping?

 

Wrapping radio button/checkbox

http://blogs.msdn.com/jfoscoding/articles/478300.aspx

 

Wrapping text

http://blogs.msdn.com/jfoscoding/articles/478299.aspx

 

 Accessibility and Mnemonics considerations:

Some controls in windows forms pick up their accessible names from the previous item in the tab order. E.g. a text box can pick up its accessible name from the label preceding it. If you have a label which describes a text box or combo box, you should set the TabIndex of the label to be one less than the TabIndex of the text box.

 

Resizable dialogs require that controls are present that the user may want to resize to better use. In general, items such as labels and buttons will not need to be modified by the user. They will be covered by auto-layout. Controls that do need to be resizable are multi-line text boxes, data grids, etc...

 

To set up a resizable form, set the columns and rows that should grow to a percentage style. The TLP  and the form should not be set to autosize. This will get us into problems with being able to resize larger without being able to resize the dialog smaller again. Default padding and margins around the borders will suffice. The TLP should be anchored top, bottom, left, right.

 

The controls that need to grow will need to be anchored top, bottom, left, right. The other controls should be anchored however you want them to look on the form.

 

Here are two screenshots of a resizable form before and after resizing.