Click here to Skip to main content
Click here to Skip to main content

Dynamically Created Controls in ASP.NET

, 27 Aug 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
How to dynamically create controls in an ASP.NET page.

Introduction

Adding controls to an ASP.NET WebForm at runtime is a simple task:

private void Page_Load(object sender, System.EventArgs e)
{
    Button newButton = new Button();
    newButton.Text = "New Button"; 
    newButton.ID = "newButton"; 
    newButton.Click += new System.EventHandler(this.newButton_Click); 

    WebUserControl1 newUserControl = 
           (WebUserControl1)LoadControl("WebUserControl1.ascx"); 
    newUserControl.ID = "newUserControl";
    this.PlaceHolder.Add(newUserControl); 
    this.PlaceHolder.Add(newButton);
}

Problem

Now, let's raise a bit little. What if we want to add a new control as a result of some user action (button click, for example)? We are moving the same code from Page_Load to Button_Click event and… here troubles begin. Our controls will show as expected, but only the first time. Any postback will reset the page to its original state. Dynamically created controls will be unable to fire any event. What is happening here? The answer is simple. Page class is stateless. It is destroyed after rendering. Page recreates child controls collection, based on tags in aspx file, then postback data can be handled and event handlers attached (in OnInit event). Controls we just created dynamically do not exist in aspx file; Page has no knowledge about them.

Solution

The solution is also simple. We have to recreate controls on load stage of page lifecycle. After it's done, each control can handle its postback data, retrieve saved viewstate, raise events etc.

Now, the code skeleton will look like this:

private void Page_Load(object sender, System.EventArgs e)
{
    RecreatePersistedControls();
}
private void Button_Click(object sender, System.EventArgs e)
{
    CreateControl("newControl");
    PersistControl("newControl");
}
private void RecreatePersistedControls()
{
    // Call CreateControl for each persisted control
}
private void CreateControl(string id)
{
    // Create controll with specified id, 
    // add it to controls collection, attach event handlers
}
private void PersistControl(string id)
{
    // Persist specified id (in session for example)
}

Download source files to see the fully functional sample.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Leon Langleyben
Web Developer
Israel Israel
Leon works as Chief Architect at SRL Group. He leads architectural design and development of various enterprise level projects.
You can meet him on user groups, conferences and forums dedicated to Architecture, ASP.NET, Team System etc. or join him for the next white water rafting adventure

Comments and Discussions

 
QuestionValidating and save Dynamically created server side controls data into database Pinmemberankushbelorkar15-Feb-13 22:02 
QuestionAnother link Pinmembersandip_frm_NEPAL22-Jun-12 5:52 
Questiontotally dynamic controls Pinmembermathewtinu25-Apr-12 10:59 
Questionusing vb? PinmemberJavaCookies19-Jan-12 20:24 
AnswerRe: using vb? PinmemberMember 815202111-Dec-14 22:42 
AnswerExcellent! Pinmemberhungvm26-Mar-09 0:34 
Questionhow to add events to dynamically created and binding links PinmemberMember 40714403-Mar-09 4:32 
AnswerRe: how to add events to dynamically created and binding links Pinmemberamit_jain_online15-Apr-12 23:15 
QuestionHow do you find the path to the control later? Pinmembermicha.gluskin25-Nov-08 5:49 
GeneralAfter the Post back, control is disappeared. Pinmemberantonyvijayan3-Jun-08 2:38 
GeneralRe: After the Post back, control is disappeared. Pinmemberantonyvijayan15-Jul-08 0:25 
QuestionProb with dynamic menulist event at runtime PinmemberHarry Sun7-May-08 4:34 
QuestionImageButton help Pinmemberjdanastasi5-Apr-08 23:15 
GeneralBig Thankx Pinmemberjoeizzy24-Jun-07 17:43 
QuestionAdding controls in flow layout Pinmembermitdej10-May-07 21:56 
QuestionHow do I add radio Buttons in a table row and control them programatically Pinmembercyprosoft23-Feb-07 8:28 
Generalprob with fire eventhandeler for Dynamically Created Controls in ASP.NET Pinmemberchiluka satish16-Feb-07 13:14 
GeneralTHANK YOU THANK YOU THANK YOU THANK YOU THANK YOU Pinmemberbmatz18-Oct-06 7:38 
Questionhow to add new controls and fire its event at runtime Pinmemberdearvivek25-Sep-06 21:32 
GeneralWorks for LinkButton but not ImageButton PinmemberAndy R Hore27-Feb-06 5:39 
GeneralRe: Works for LinkButton but not ImageButton Pinmembermbsum3-Sep-06 22:09 
Generaldynamic controls and the control tree PinsussAnonymous17-Jul-05 15:37 
GeneralDynamically adding a user control based on an event from another control Pinmembersempko13-Jul-05 20:46 
Ok, this is what I've been trying to do all day:
 
Dynamicaly add a user control to an ASP.Net web page in the position of a placeholder. Then, when a user selects a different node in a treeview control, postback the page and load a different user control based upon the Text property of the selected node.
 
The main problem with this despite my best efforts is that the recommended way to load a dynamic control is in the Page_init event handler, however, this only works if the control that is loaded is of the same type on every post back otherwise the server will throw a 'Failed to load viewstate...' error. In this scenario, the user control could be a different one on each postback, so this could not work for me.
 
The other problem is that when you put the code to dynamicaly load the user control in the Page_init event handler, since this is a SelecteNodeIndexChange event, there is no way to determine the new value before the Page_Init is called. I have tried everything, even overriding the DeterminePostBackMode event handler which does come before Init. however, there is no way to access properties of Controls at this point becuase it takes place after the page has been posted back and before the LoadViewState occurs. So, what kept happeneing is that the dynamically loaded control would be the same as it was on the post back before and only on the next post back would it be the correct user control. Again, that is becuase the SelectedNodeIndexChange value doesn't really update until after the postback and after the Init event.
 
What I did:
 
So on the 1st Page_Load event I go ahead and do the following:
 
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Put user code to initialize the page here
If Not Page.IsPostBack Then
Session("IsPostBack") = True
FillTree(oTree) 'fills my treeview control with parent nodes
FillList2() 'fills the child nodes for each parent node in the treeview
LoadUserControl() 'routine to load control in the placeholder controls collection
BindUserControl() 'routine to bind the child controls of the User Control
Else
SetSelectedIndex() 'Determines the SelectedIndex of the treeview after a postback
LoadUserControl()
BindUserControl()
End If
 
End Sub
 

The actual code to add the control to the placeholder is inside my LoadUserControl() method within a Select Case block using the Session("ControlToLoad") as the case and looks like such (select case not shown):
 
Private Sub LoadUserControl()
uc = LoadControl("~/Controls/DynamicUserControl1.ascx")
uc.ID = "DynamicUserControl1" 'can be any id you wish though you might want to make it unique for each type of possible user control you plan to load just for safety.
ph.Controls.Add(uc)
End Sub
 
Note: 'uc' was declared as Protected Withevents uc as Control and 'ph' was a placeholder added to my web form in design view.

This adds a dynamically determined user control to my static placeholder (ph)controls collection,not the page's controls collection, on the first trip to the page. Then when I go to bind any of the controls in this user control i just added, I have to type cast the user control in order to call any methods or properties in the code-behind pages of that user control. i do this like such inside of my BindUserControl() method inside of another Select Case block to determin again which tpype of control was added (select case not shown):
 
CType(uc, DynamicControl1).BindControls(arguments) 'BindControls would be a method in the DynamicControl1.ascx.vb file, not the code-behind file of the current .aspx page.
 
One thing to note is that I could have put the above code inside of the LoadUserControl() method and saved myself the trouble of writing redundant Select Case blocks.
 
Now, the hard parts - when a user clicks on a certain node in my Treeview control, I want to load a different type of user control depending upon the Text property of the selected tree node. I determined this in the SetSelectedIndex() method as such:
 
Session("ControlToLoad") = oTree.GetNodeFromIndex(oTree.SelectedNodeIndex).Text 'oTree = TreeView control
 
Now, remember that I can only determine the Text property of the selected node after the page has been re-initialized in the page load event, but I also must make sure that the new control that is to be loaded is of the same type of control as was before the postback. Why? becuase the LoadViewState expects to load the viewstate of the control that was there not the new one you plan to load.
 
So once I've determined the new user control to load and enter my routine to actualy load it, I have to make sure I have logic in place to do the following:
 
1) Make sure I add the control that was added on the first trip to the page to a Session variable, so I can compare it on subsequent trips
2) If this is a subsequent trip to the page then I need to compare the user control store in my session variable to that of the new user control that is to be added. All I did here was make sure to set the ID property of the user control and compare the uc.ID's to each other.
3) If the controls have the same ID's then they are the same, so simply add the new control that you determined from the Session("ControlToLoad") variable.
4)If the controls do not have the same ID's then we need to load the control that was on teh previous postback first, so that when the recursive loadviewstate function is called on it, it's viewstate is loaded and the error that we were getting before will not appear.
5) Remove the old user control from the placeholder's collection and add the new control as determined by the Session("ControlToLoad") variable.
 
So, as you see in the above logic, that you will load the control determined by the Session("ControlToLoad") variable no matter what, but you just need to make sure that if you are loading a different control than before, that you load the old one first to satisfy the viewstate and then delete it and load the new one it's place and all is well. One thing I was concerned about was seeing the first control load and the dissapear and then the new control load, however, since we are doing all of this in the Page_load event, it's seemless and works well.
 
Hope this workaround helps somebody.
 
later!
 

 
JasonERivera.com
GeneralRe: Dynamically adding a user control based on an event from another control PinsussAnonymous28-Aug-05 15:00 
GeneralPage Load Occurs first on Button Click Event PinsussAnonymous11-May-05 21:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 28 Aug 2004
Article Copyright 2004 by Leon Langleyben
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid