[Part 2/2] ASP.NET: Dynamic User Controls
How to dynamically generate controls including UserControls? Same as adding windows controls:
STEP 1: Add
STEP 2: Draw/Redraw
STEP 3: Read
STEP 1: Add
STEP 2: Draw/Redraw
STEP 3: Read
Let’s say we have DataTable having following data in it:
ID CAPTION DATATYPE
1 Name Text2 Sports List
3 Date Date
The UserControl contains a TextBox for date string, ImageButton showing a Calendar image; and a Calendar control itself shown/hide when the Calendar image is clicked, see fig1.
FIG1: UCtlCalendar user control.
Note that events are mapped and are working for dynamically generated UserControl.
Following is the output(fig2) that is desired; TextBox controls, a ListBox, and a UserControl.
FIG2: Desired output with dynamic controls.
Following illustration (fig3) the Calendar control upon click event.
FIG3: WebUserControl click event
Let’s follow same 4 stepped procedure.
STEP 1: Add a PlaceHolder control called phControls
STEP 2: Draw dynamic controls
STEP 3: Redraw dynamic controlsprivate void DrawControls(DataTable dtTable)
{
Hashtable htControls = new Hashtable();
try
{
for (int i = 0; i < dtTable.Rows.Count; i++)
{
//Generate in following order
//1. Label, to display caption
//2. And a control attached to label.
DataRow drRow = dtTable.Rows[i];
Label theLabel = new Label();
theLabel.Width = new Unit(Constants.ControlSizePercentage);
theLabel.Text = drRow["CAPTION"].ToString();
phControls.Controls.Add(theLabel);
ViewState["Label" + i.ToString()] = theLabel.Text; //save the label control
if (drRow["DATATYPE"].ToString() == "TextBox")
{
TextBox ctl = new TextBox();
ctl.Width = new Unit(Constants.ControlSizePercentage);
ctl.ID = "objControl" + i.ToString();
phControls.Controls.Add(ctl);
//Add in the hashtable
htControls.Add(i, "TextBox");
}
else if (drRow["DATATYPE"].ToString() == "List")
{
//Pull and save the ddp list.
ListBox ctl = new ListBox();
ctl.Width = new Unit(Constants.ControlSizePercentage);
ctl.ID = "objControl" + i.ToString();
ctl.SelectionMode = ListSelectionMode.Multiple;
phControls.Controls.Add(ctl);
htControls.Add(i, "List");
//Options:
//1. Add list items here manually... OR
//2. Get the item list from database and bind with list box.
}
else if (drRow["DATATYPE"].ToString() == "Date")
{
//add user control
Control ctl = LoadControl("~/UI/UserControls/UCtlCalendar.ascx");
ctl.ID = "objControl" + i.ToString();
phControls.Controls.Add(ctl);
htControls.Add(i, "Date");
}
}
ViewState.Add("htControls", htControls);
}
catch (Exception ex)
{
Error("Problem! " + ex.ToString());
}
}
private void RedrawControls()
{
try
{
Hashtable htControls = (Hashtable)ViewState["htControls"];
for (int i = 0; i < htControls.Count; i++)
{
Label theLabel = new Label();
theLabel.Width = new Unit(Constants.ControlSizePercentage);
theLabel.Text = ViewState["Label" + i.ToString()].ToString(); //Reload the labels.
phControls.Controls.Add(theLabel);
if (htControls[i].ToString() == "TextBox") //Print text box.
{
TextBox ctl = new TextBox();
ctl.Width = new Unit(Constants.ControlSizePercentage);
ctl.ID = "objControl" + i.ToString();
phControls.Controls.Add(ctl);
}
else if (htControls[i].ToString() == "List")
{
ListBox ctl = new ListBox();
ctl.Width = new Unit(Constants.ControlSizePercentage);
ctl.ID = "objControl" + i.ToString();
phControls.Controls.Add(ctl);
//Set list box items, if any.
}
else if (htControls[i].ToString() == "Date")
{
//1. Load a UserControl
Control ctl = LoadControl("~/UI/UserControls/UCtlCalendar.ascx");
//2. Assign an ID
ctl.ID = "objControl" + i.ToString();
((Calendar)ctl.FindControl("cldDate")).SelectedDate = DateTime.Now.Date;//Assign a default date
//3. Add to PlaceHolder control
phControls.Controls.Add(ctl);
}
}
}
catch (Exception ex)
{
Error("Problem! " + ex.ToString());
}
}
STEP 4: Read from dynamically generated user controls
private string ReadTextFromControls()
{
StringBuilder sbResponse = new StringBuilder();
try
{
Hashtable htControls = (Hashtable)ViewState["htControls"];
sbResponse.Append("?");
for (int i = 0; i < htControls.Count; i++)
{
sbResponse.Append(ViewState["Label" + i.ToString()].ToString());
sbResponse.Append("=");
if (htControls[i].ToString() == "TextBox") //Print text box.
{
sbResponse.Append(((TextBox)phControls.FindControl("objControl" + i.ToString())).Text);
}
else if (htControls[i].ToString() == "List")
{
ListBox ctl = ((ListBox)phControls.FindControl("objControl" + i.ToString()));
for (int j = 0; j < ctl.Items.Count; j++)
{
if (ctl.Items[j].Selected)
sbResponse.Append(ctl.Items[j].Text + ",");//make it comma separated.
}
sbResponse.Remove(sbResponse.ToString().Length - 1, 1); //remove the last extra comma.
}
else if (htControls[i].ToString() == "Date") //Print text box.
{
//1. Find calendar control
Control ctl = phControls.FindControl("objControl" + i.ToString());
//2. Get the date string
str = ((Calendar)ctl.FindControl("cldDate")).SelectedDate.ToShortDateString();
sbResponse.Append(str);
}
sbResponse.Append("&");
}
if (sbResponse.ToString().EndsWith("&"))
{
sbResponse.Remove(sbResponse.ToString().Length - 1, 1);//remove the last character!
}
}
catch (Exception ex)
{
Error("Problem! " + ex.ToString());
}
return sbResponse.ToString();
}
Usage is same:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
DrawControls();//First time, just draw
}
else
{
RedrawControls();//Other times, redraw existing controls.
}
}
Happy Dynami’zing the controls (0;