Adding Dynamic Controls in ASP.NET

12,186

You need to have the logic in your click handler add to the panel's Controls collection as well as to the list of controls, like this:

protected void btnAddAddress_Click(object sender, EventArgs e)
{
    AddressUserControl aCntrl = LoadControl("~/UserControls/AddressUserControl.ascx") as AddressUserControl;
    addresses.Add(aCntrl);
    phAddresses.Controls.Add(aCntrl);
}

UPDATE:

In your user control, you need to define an event that can be defined in the page that hosts the user control, like this:

AddressUserControl.cs (code-behind):

public event EventHandler RemoveAddress;

protected void removeAddressUserControlButton_Click(object sender, EventArgs e)
{
    // Find out if the event has been set, if so then call it
    if (this.RemoveAddress!= null)
    {
        RemoveAddress(sender, e);
    }
}

Now on your page where you are using the user control, do this:

// Wire up the user control's event
nameOfUserControl.RemoveAddress += new EventHandler(addressUserControlButton_Click);

Finally, implement the addressUserControlButton_Click event:

protected void addressUserControlButton_Click(object sender, EventArgs e)
{
    // Do your dynamic control creation here or whatever else you want on the page
}
Share:
12,186

Related videos on Youtube

Admin
Author by

Admin

Updated on August 02, 2022

Comments

  • Admin
    Admin over 1 year

    It kind of seems to me that there is an inherent difficulty in dynamically adding controls in ASP.NET Web Forms. Specifically, for a dynamically added control to be included in the ViewState, and have it's events properly wired up and so forth it is suggested that these be added during the Page_PreInit event.

    That said, many times we'll probably want to add such controls according to an event, such as a user clicking a button. Control specific events like Click events always run after Init, and even after Load. Supposed the following .aspx....

     <form id="form1" runat="server">
        <div>
          <asp:PlaceHolder ID="phAddresses" runat="server"></asp:PlaceHolder>
           <br /><br />
            <asp:Button ID="btnAddAddress" runat="server" Text="Add Another Address" OnClick="btnAddAddress_Click" />
    

    ...and the following .aspx.cs....

    private static List<AddressUserControl> addresses = new List<AddressUserControl>();
    
    
    
    
    protected void Page_PreInit(object sender, EventArgs e)
      {
    
       foreach (AddressUserControl aCntrl in addresses)
        {
          phAddresses.Controls.Add(aCntrl);
           // Helper to find button within user control
         addressButtonControl = findAddressControlRemoveButton(aCntrl);
         addressUserControlButton.ID = "btnRemoveAddress" + addressCount;
         addressUserControlButton.Click += new EventHandler(addressUserControlButton_Click);
         addressCount++;
        }
      }
    
     protected void btnAddAddress_Click(object sender, EventArgs e)
     {
      AddressUserControl aCntrl = LoadControl("~/UserControls/AddressUserControl.ascx")                 as    AddressUserControl;
     addresses.Add(aCntrl);
     }
    

    Now in the above situation the number of User Controls displayed is always one behind the number the user has actually added, because the Click event doesn't run until after PreInit, where controls must be added to the placeholder. I must be missing something here, because this seems inherent to the ASP lifecycle, and to require some 'hack' or other.

    EDIT - Yeah for some reason EventHandlers I add during btnAddress_Click() won't run, only EventHandlers I add during Page_Init, or declaratively in markup. This is what I tried to do...

    protected void btnAddAddress_Click(object sender, EventArgs e)
     {
       AddressUserControl aCntrl = LoadControl("~/UserControls/AddressUserControl.ascx") as AddressUserControl;
      addresses.Add(aCntrl);
      phAddresses.Controls.Add(aCntrl);
      findAddressControlRemoveButton(aCntrl);
      addressUserControlButton.ID = "btnRemoveAddress" + addresses.Count;
    
                    ///////////////////////////////////////////////////////////////////////////////////
                    // ADDED EVENT HANDLER HERE
                    //////////////////////////////////////////////////////////////////////////////////////
      addressUserControlButton.Click += new E ventHandler(addressUserControlButton_Click);
    
      }
    

    ...but the event won't fire as I've said. Any ideas?

    EDIT - Here's the markup for my AddressUserControl. There's no logic in the code behind file

    <%@ Control Language="C#" ClassName="AddressUserControl" AutoEventWireup="true" CodeBehind="AddressUserControl.ascx.cs" Inherits="XFAWithUserControl.UserControls.AddressUserControl" %>
    
    
        <asp:Panel ID="pnlAddressForm" runat="server">
            <asp:Label ID="lblStreet" runat="server" Text="Street Address"></asp:Label>
               <asp:TextBox ID="txtStreet" runat="server"></asp:TextBox>
                 <br /><br />
                <asp:Label ID="lblCity" runat="server" Text="City"></asp:Label>
                <asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
                <br /><br />
                <asp:Label ID="lblState" runat="server" Text="State"></asp:Label>
                <asp:TextBox ID="txtState" runat="server"></asp:TextBox>
                <br /><br />
                <asp:Label ID="lblZip" runat="server" Text="Zip"></asp:Label>
                <asp:TextBox ID="txtZip" runat="server"></asp:TextBox>
                <br /><br />
                <asp:Button ID="btnRemoveAddress" runat="server" Text="Remove Address" />
            </asp:Panel>
    

    right now my click event for btnRemoveAddress is just something silly like this...

     private void addressUserControlButton_Click(object sender, EventArgs e)
      {
        Button thisButton = sender as Button;
        thisButton.Text = "Why Hello";
      }
    

    but my goal is to have it remove the associated AddressUserControl, so that a user can add and/or remove an arbitrary number of AddressUserControls from the page by clicking buttons.

    EDIT - Here's what I have now, still doesn't work

    protected void btnAddAddress_Click(object sender, EventArgs e)
            {
                AddressUserControl aCntrl = LoadControl("~/UserControls/AddressUserControl.ascx") as AddressUserControl;
                addresses.Add(aCntrl);
                phAddresses.Controls.Add(aCntrl);
                findAddressControlRemoveButton(aCntrl);
                addressUserControlButton.ID = "btnRemoveAddress" + addresses.Count;
                aCntrl.ChangeText += new EventHandler(addressUserControlButton_Click);
            }
    
    private void addressUserControlButton_Click(object sender, EventArgs e)
    {
        Button thisButton = sender as Button;
        thisButton.Text = "Why Hello";
    }
    

    AddressUserControl.ascx

    <asp:Panel ID="pnlAddressForm" runat="server">
        <asp:Label ID="lblStreet" runat="server" Text="Street Address"></asp:Label>
        <asp:TextBox ID="txtStreet" runat="server"></asp:TextBox>
        <br /><br />
        <asp:Label ID="lblCity" runat="server" Text="City"></asp:Label>
        <asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
        <br /><br />
        <asp:Label ID="lblState" runat="server" Text="State"></asp:Label>
        <asp:TextBox ID="txtState" runat="server"></asp:TextBox>
        <br /><br />
        <asp:Label ID="lblZip" runat="server" Text="Zip"></asp:Label>
        <asp:TextBox ID="txtZip" runat="server"></asp:TextBox>
        <br /><br />
        <asp:Button ID="btnRemoveAddress" runat="server" Text="Remove Address" OnClick="btnRemoveAddress_Click" />
    </asp:Panel>
    

    AddressUserControl.ascx.cs

    public event EventHandler ChangeText;
    
    
    
       protected void Page_Load(object sender, EventArgs e)
        {
    
        }
    
        public void btnRemoveAddress_Click(object sender, EventArgs e)
        {
            if (this.ChangeText != null)
            {
                ChangeText(sender, e);
            }
        }