Feature Post

Top

[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

Let’s say we have DataTable having following data in it:
ID           CAPTION             DATATYPE
1             Name                   Text
2             Sports                   List
3             Date                     Date

Based upon above DATATYPE field, we need to generate controls; and in case of Date, we have a user control (WebUserControl) called UCtlCalendar control that we need to generate and keep track of.

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

private 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()); 
        } 
} 

STEP 3: Redraw dynamic controls

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;