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.
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:
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.
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:
Additionally the tableLayoutPanel provides several methods to change the position of controls that are already added to the table:
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:
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.
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.
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.
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:
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:
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:
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:
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:
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.
Specifies the number of rows to create
Specifies the number of columns to create
specifies the minimum number of rows to create, more will be created if needed.
Specifies the number of columns to create
specifies the number of rows to create.
Columns property specifies the minimum number of rows to create, more will be created if needed.
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.
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.
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
public int GetColumnSpan(Control control);
public void SetColumnSpan(Control control, int value);
Specify how many columns this control should span. (default is 1)
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.
Here is the scenario:
Simply setting Button.AutoSize=true would cause the buttons to have unequal size, ala:
The buttons now will resize correctly.
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:
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.
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.
What are the the techniques for text wrapping?
Wrapping radio button/checkbox
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.