Friday, September 12, 2008

Sharpening The C# Program

Sharpening The C# Program

I decided that all this positioning of controls in dialog windows was really ugly and clumsy, so I decided to use the TableLayoutPanel container instead. It lets you define an table, very much like HTML uses for displaying tables, and you can position stuff at (col, row) within the table.

The first try worked fine--but every cell in the table was used, and it worked fine. When I tried another dialog window, where some of the cells were empty (for example, on the first row), I could not get it to work correctly. Nor could I find an example using the SetRow and SetColumn methods anywhere.

So I changed to using TableLayoutPanel.Add(control, column, row) instead--and it worked just great! Then I fancied it up a bit by changing from the default font for some of the items:

// Bring up a dialog box to ask which links to print.
Form dlgWebPage = new Form();
TableLayoutPanel panel = new TableLayoutPanel();
panel.RowCount = 4;
panel.ColumnCount = 6;
Label printChoices = new Label();
printChoices.Font = new Font("Arial", 12, FontStyle.Bold, System.Drawing.GraphicsUnit.Point);
printChoices.Text = "Which Links To Print?";
printChoices.AutoSize = true;
panel.Controls.Add(printChoices, 3, 0);
Much nicer! There's still some work to take advantage of some of the docking and anchoring capabilities of TableLayoutPanel, but I'm learning one thing at a time.

Also, I decided that I really wanted these dialog windows to resize themselves to exactly fit the controls contained therein. The strategy that I used was to record the maximum X and Y values of the controls within the panel as I added each control:
maxX = Math.Max(maxX, printChoices.Location.X + printChoices.Size.Width);
maxY = Math.Max(maxY, printChoices.Location.Y + printChoices.Size.Height);
I can probably smarten this up to a single function call to which I pass some struct that includes maxX and maxY, and the control. I'll do that tomorrow, I think.

Then, when I am ready to add the panel to the dialog window:
panel.ClientSize = new System.Drawing.Size(maxX, maxY);
dlgWebPage.Controls.Add(panel);
This makes the interior of the panel (the client size) the size of the most extreme outlier of the controls. Then:
dlgWebPage.ClientSize = panel.Size;
This makes the client size of the dialog window the size of the exterior of the panel. Much more elegant!

UPDATE: I'm getting ready to go to bed, so I'm not going to update the source tonight, but the change to factor out the common code was actually quite elegant:
private void maxCoord(ref Point max, Control control)
{
max.X = Math.Max(max.X, control.Location.X + control.Size.Width);
max.Y = Math.Max(max.Y, control.Location.Y + control.Size.Height);
}
In the function that creates the dialog window:
// Keep track of the farthest point down and right within the panel.
Point max = new Point(0, 0);
...
panel.Controls.Add(printChoices, 3, 0);
maxCoord(ref max, printChoices);
...
panel.ClientSize = new System.Drawing.Size(max.X, max.Y);
dlgWebPage.Controls.Add(panel);
dlgWebPage.AutoSize = true;
dlgWebPage.ClientSize = panel.Size;
The next phase of elegance would be to derive a class from TableLayoutPanel that does this for me when I call the Add method, so that it records the coordinates somewhere, and then uses them to resize the client.

No comments:

Post a Comment