Introduction
The following program was written in order to share the technics needed to implement the dynamic construction of a form. The initial idea was about writing a program in C#, that
would allow its users, to manage any kind of collection structure (coins, stamps, guns, etc...). I had to overcome 2 main challenges. First of all i needed to learn how to create in runtime, a database table, with a
dynamic name, and dynamic fields in a comprehensive way for the most basic users. Second, it became obvious that the form that would support these tables would also have to be dynamic.
You can see the result by downloading My Collections manager.
Let's focus only on the second part of the challenge, the dynamic creation of forms, also the most visual and rewarding.
First, in order to make a valid sample of what you can create with dynamic forms, I've made a little dynamic forms generator.

By running DynamicForm.exe which can be found in the DynamicForm_demo.zip file,
you will be able to access this form and create simple dynamic forms according to the parameters
you have supplied. The form that is created is very simple. Supplying labels, font, font size,
textbox size into the generator screen, it builds a form with a series of labels and textboxes, arranged vertically.
It also adds a button to demonstrate how to implement events to dynamically created objects.
Using the code
The project consists in a simple form class using standard system namespaces that you can find in any windows project:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
Creating the dynamic content is not much different from what the Editor you are using (in this case SharpDevelop) does for you at design mode and stores in the .Designer.cs file.
One of the main difficulty, was to find a way to measure the size of objects precisely. For this, the best way I've found is to use a picture box to define a graphic string so i could retrieve
its size in pixel. I don't know at that point if it's the best solution, since, for very small font size (below 5), the text in the label gets wrapped.
int intVertPos = 0;
int intMaxWidthLabel = 0;
int intWidthTextBox = 0;
int intGapHeight = 0;
string measureString = "";
Font stringFont = null;
SizeF stringSize;
int intIndex = 0;
Graphics g = pictureBox1.CreateGraphics();
TextBox dummyTextBox = new TextBox();
dummyTextBox.Font = new System.Drawing.Font(cmbFont.Text,
float.Parse(txtSizeFont.Text), System.Drawing.FontStyle
.Regular, System.Drawing.GraphicsUnit.Point,((byte)(0)));
int intHeight = int.Parse(txtSizeFont.Text) + int.Parse(
txtSizeFont.Text)/2;
dummyTextBox.Name = "TextBoxDummy";
intGapHeight = dummyTextBox.Height;
if (frm != null) frm.Close();
frm = new Form();
frm.AutoScaleDimensions =new System.Drawing.SizeF(6F, 13F);
frm.AutoScaleMode =System.Windows.Forms.AutoScaleMode.Font;
frm.Name = "frm_test";
frm.ClientSize = new System.Drawing.Size(10, 10);
frm.ControlBox = false;
frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle
.FixedSingle;
frm.AutoSizeMode = System.Windows.Forms.AutoSizeMode
.GrowAndShrink;
frm.BackColor = System.Drawing.Color.LightGray;
for (int i=0;i
Now, the only remaining issue is to add events to the objects you've created. Once again the class designer file helps you a lot, and you can copy its content widely:
btnFill.Click += new System.EventHandler(btnFillClick);
I've created a very simple function associated to this event in order to fill each textbox on the form:
private void btnFillClick(object sender,System.EventArgs e)
{
foreach (Control chcontrol in frm.Controls)
{
if (chcontrol.Name == "TextBoxTitle")
{
if (chcontrol.Text == "Filling Test")
chcontrol.Text = "Filling Test Again";
else
chcontrol.Text = "Filling Test";
}
}
}
Since every textbox in the form had the same name, I just had to create a small loop among all objects in the form and work only with those
having the same name as the textboxes. Another solution consists in creating another instance of the object and work with it just as follow:
TextBox tb = (TextBox)frm.Controls["TextBoxTitle"];
if (tb.Text == "Filling Test")
tb.Text = "Filling Test Again";
else
tb.Text = "Filling Test";
Et voil�, le tour est jou�!
Please feel free to comment this code and suggest new implentations and ideas!
History
2006-01-10: First version