Friday, 24 February 2012

Dynamic Loading of ASP.NET User Controls


Introduction

In addition to using Web Server controls in your ASP.NET web pages, you can create your own custom, reusable controls using the same techniques you use for creating ASP.NET web pages. These controls are called User Controls. A User Control is a kind of composite control that works much like an ASP.NET web page - you can add existing web server controls and markup to a User Control, and define properties and methods for the control. You can then embed them in ASP.NET web pages, where they act as a unit.
User Controls are semi-autonomous pages of HTML and underlying ASP.NET code that can be inserted into ASP.NET pages. As such, they are useful for adding blocks of functionality to pages.
Typical uses of User Controls are for use as page headers and footers. Unlike ASP.NET pages that have the .aspx file extension, User Controls typically have the .ascx file extension. Once created, in Visual Studio .NET, they can be included in a specific page by simply dragging the User Control onto the Design view of that page. Alternatively, they can be added to a page at Design time by including the following in the page's HTML. For example, the following line includes a SimpleControl User Control from the SimpleControl.ascx file:
<%@ Register src="~/usercontrols/SimpleControl.ascx" 
    tagname="SimpleControl" tagprefix="SimpleControl" %>
The User Control is then positioned on the page using the following tag:
<SimpleControl:SimpleControl id="ucSimpleControl" 
         runat="server"></SimpleControl:SimpleControl>
Although this procedure is satisfactory for content like headers and footers that will always be required on specific pages, it would be useful if there was a way of dynamically loading specific User Controls at run time.
Fortunately, it is possible to load User Controls onto a page by making use of the LoadControl method. This function has a straightforward syntax - it takes a single argument - the virtual path to the User Control page. For example, to load the SimpleControl User Control, the following C# code would be used within the Page_Loadmethod, or you can use this on the Click event of the button:
usercontrols_SimpleControl ucSimpleControl = 
  LoadControl("~/usercontrols/SimpleControl.ascx") 
  as usercontrols_SimpleControl;
Once the User Control has been loaded, it can be added to the page by adding it to the Controls collection:
Placeholder1.Controls.Add(ucSimpleControl);

Using the Code

First, let's create a User Control and populate it with several controls. The User Control content looks like this:
<table>
    <tr>
        <td><asp:Label ID="label1" runat="server" 
            Text="First Name" ></asp:Label></td>
        <td> <asp:TextBox ID="txtFirstName" 
            runat="server"></asp:TextBox></td>
    </tr>
     <tr>
        <td><asp:Label ID="label2" runat="server" 
           Text="Last Name" ></asp:Label></td>
        <td> <asp:TextBox ID="txtLastName" 
           runat="server"></asp:TextBox></td>
    </tr>
    <tr>
        <td><asp:Button ID="btnPost"  runat="server" 
            Text="Send Info" OnClick="btnPost_Click" />
        </td>
    </tr>
</table>
Create a delegate just under the namespaces to handle the Click event in the Default.aspx page. After declaring the delegate, create the delegate instance which will be called from the virtual method of the btnPost's click.
public delegate void btnPost_Click(object sender, System.EventArgs e);

public partial class usercontrols_SimpleControl : 
       System.Web.UI.UserControl
{
    #region Public Event

    public event btnPost_Click btnPostClk;

    #endregion

    #region Public Properties

    public TextBox FirstName
    {
        get
        {
            return txtFirstName;
        }
        set
        {
            txtFirstName = value;
        }
    }

    public TextBox LastName
    {
        get
        {
            return txtLastName;
        }
        set
        {
            txtLastName = value;
        }
    }
    #endregion

    #region Vitual Methods

    protected virtual void OnbtnDelQtnMrClk(EventArgs e)
    {
        // Call btnPost_Click event delegate instance
        btnPostClk(this, e);
    }

    #endregion

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    protected void btnPost_Click(object sender, EventArgs e)
    {
        //Call Virtual Method
        OnbtnDelQtnMrClk(e);
    }
}
Now, go to the ASPX page where you want to add the User Control and register the User Control by registering the tag in HTML view. The ASPX page content looks like this:
<%@ Register src="~/usercontrols/SimpleControl.ascx" 
    tagname="SimpleControl" tagprefix="SimpleControl" %>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>This is example of how to add usercontrol dynamically</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
            <asp:Button ID="btnAddControl" runat="server" 
              Text="Click to add SimpleControl" 
              onclick="btnAddControl_Click" />
            <br />
            <asp:PlaceHolder runat="server" 
               ID="Placeholder1" ></asp:PlaceHolder>
            <br />
            <asp:Label ID="lblUser" 
              runat="server"></asp:Label>

    </div>
    </form>
</body>
</html>
To add the User Control on the Click event of "btnAddControl", add the following code to the code-behind:
protected void btnAddControl_Click(object sender, EventArgs e)
{
    // Create instance of the UserControl SimpleControl
    usercontrols_SimpleControl ucSimpleControl = 
      LoadControl("~/usercontrols/SimpleControl.ascx") 
      as usercontrols_SimpleControl;
    
    // Set the Public Properties
    ucSimpleControl.FirstName.Text = "Milind";
    ucSimpleControl.LastName.Text = "Chavan";

    //Create Event Handler for btnPost Click 
    ucSimpleControl.btnPostClk += 
            new btnPost_Click(ucSimpleControl_btnPostClk);

    //Add the SimpleControl to Placeholder
    Placeholder1.Controls.Add(ucSimpleControl);

    // Add the instance of the SimpleControl to Session Variable
    Session.Add((Session.Count + 1).ToString(), ucSimpleControl);

    // Set createAgain = true
    createAgain = true;
}

void ucSimpleControl_btnPostClk(object sender, EventArgs e)
{
   usercontrols_SimpleControl ucSimpleControl = 
               ((usercontrols_SimpleControl)(sender));
   lblUser.Text = "Welcome " + ucSimpleControl.FirstName.Text + 
                  " " + ucSimpleControl.LastName.Text;
}
The most important thing is, after the postback, the User Control vanishes from the page. So to maintain the User Control and its controls' properties as well as events, we need to add this instance of the User Control to the session variable shown above. To generate the User Control again on postback, we use the OnPreInit event:
// Declare 2 variable to handle user control after postback
const string controlID = "MyUserControl";
static bool createAgain = false;

protected Control GetPostBackControl(Page page)
{
    Control control = null;
    try
    {
        string ctrlName = page.Request.Params.Get("__EVENTTARGET");

        if (ctrlName != null && ctrlName != String.Empty)
        {
            control = page.FindControl(ctrlName);
        }
        else
        {
            ContentPlaceHolder cph = 
              (ContentPlaceHolder)page.FindControl("Main");
            for (int i = 0, len = page.Request.Form.Count; i < len; i++)
            {
                string[] ctl = page.Request.Form.AllKeys[i].Split('$');
                if (ctl.Length > 2)
                {
                    control = cph.FindControl(ctl[2]) 
                              as System.Web.UI.WebControls.Button;
                }

                if (control != null) break;
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return control;
}

protected override void OnPreInit(EventArgs e)
{
    base.OnPreInit(e);

    Control control = GetPostBackControl(this.Page);

    // Check if the postback is caused by the button 
    // Titled "Click to Create a Dynamic Control"
    // OR
    // createAgain field is true 
    // which means a call is made to the server while the 
    // user control is active  

    if ((control != null && control.ClientID == 
                    btnAddControl.ClientID) || createAgain)
    {
        //should be set before the CreateUserControl method
        createAgain = true;

        CreateUserControl(controlID);
    }
}

protected void CreateUserControl(string controlID)
{
    // createAgain field is set to true in the OnPreInit method
    // when the 'Create User Control' button is clicked 

    // the createAgain field is used to check if the
    // user control is on the page before the call 
    // if so create the control again and add it to the
    // Control Hierarchy again
    try
    {
        if (createAgain && Placeholder1 != null)
        {
            if (Session.Count > 0)
            {
                Placeholder1.Controls.Clear();
                for (int i = 0; i < Session.Count; i++)
                {
                    switch (Session[i].ToString())
                    {
                        case "ASP.usercontrols_simplecontrol_ascx":
                        {
                            // Create instance of the UserControl SimpleControl
                            usercontrols_SimpleControl ucSimpleControl = 
                              LoadControl("~/usercontrols/SimpleControl.ascx") 
                              as usercontrols_SimpleControl;

                            // Set the Public Properties
                            ucSimpleControl.FirstName.Text = 
                              ((usercontrols_SimpleControl)(Session[i])).FirstName.Text;
                            ucSimpleControl.LastName.Text = 
                              ((usercontrols_SimpleControl)(Session[i])).LastName.Text;

                            //Create Event Handler for btnPost Click 
                            ucSimpleControl.btnPostClk += 
                              new btnPost_Click(ucSimpleControl_btnPostClk);

                            //Add the SimpleControl to Placeholder
                            Placeholder1.Controls.Add(ucSimpleControl);
                            break;
                        }
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
I know this is one of the known techniques, but I hope it has given you another way to think about dynamically adding controls.

No comments:

Post a Comment