Click here to Skip to main content
15,879,096 members
Articles / Web Development / ASP.NET
Article

Retaining State for Dynamically Created Controls in ASP.NET applications

Rate me:
Please Sign up or sign in to vote.
4.74/5 (65 votes)
18 Feb 20032 min read 521K   91   53
When creating controls on the fly on your ASP.NET pages viewstate is a bit hard to track. Learn how it works and how to help your application remembers where to put what.

Introduction

When dynamically adding controls to an ASP.NET page in runtime the object references are lost at postback because they have no handle in the codebehind. The values entered by the user is not availible when accessing these objects after postback, and they seem empty. This article describes how to use ViewState to recreate and reinsert the postback values into the objects to access their values.

Background

An ASP.NET application with pages that use dynamic generation of controls that need to retain state across postbacks. The solution described in this paper enables you to create a totally dynamic number of controls at runtime and retreive their values after postback.

Solution

Dynamically added controls have no object reference variable in the codebehind class. They appear only in the control collection of the containing control, i.e. the Page.Controls collection. When the page is posted back to the server as a result of user interaction a new instance of the codebehind class is instantiated, and all the variables of the class is set with values from the ViewState.

This means that the objects we are accessing from the codebehind class, that "feels" like the same objects as we worked on before postback, actually are new ones that got their predecessors values via ViewState and ASP.NET state management.

So, the controls that were dynamically created are no longer there and consequently the values returned from these controls have no place to go. They are lost in the viewstate.

In order to catch these values the dynamically generated controls needs to be re-generated at Page_Load. The important thing is to assign the same ID to each control. The ViewState uses the ID property of the Control objects to reinstate the values.

Add the following elements to your System.UI.Page class:

C#
public class DynamicallyAddingControls : System.Web.UI.Page
{
    // a Property that manages a counter stored in ViewState
    protected int NumberOfControls
    {
        get{return (int)ViewState["NumControls"];}
        set{ViewState["NumControls"] = value;}
    }

    private void Page_Load(object sender, System.EventArgs e)
    {
        if(!Page.IsPostBack)
            //Initiate the counter of dynamically added controls
            this.NumberOfControls = 0;                
        else
            //Controls must be repeatedly be created on postback
            this.createControls();
    }

    // This routine creates the controls and assigns a generic ID
    private void createControls()
    {
        int count = this.NumberOfControls;

        for(int i = 0; i < count; i++)
        {
            TextBox tx = new TextBox();
            tx.ID = "ControlID_" + i.ToString();
            //Add the Controls to the container of your choice
            Page.Controls.Add(tx);
        }
    }

    // example of dynamic addition of controls
    // note the use of the ViewState variable
    private void addSomeControl()
    {
        TextBox tx = new TextBox();
        tx.ID = "ControlID_" + NumberOfControls.ToString();

        Page.Controls.Add(tx);
        this.NumberOfControls++;
    }

}

Note that the createControls method has to simulate the way that you dynamically built your page before the postback. The important thing here is obviously to assign identical ID values to the correct type of controls to that we can access them at postback.

Points of Interest

This solution works because the ASP.NET ViewState supports dynamically added controls, but does not do the re-generation for us. As long as the ID properties match ASP.NET does the rest of the job for us.

Thanks to Eric Sütter for providing valuable input on this article!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
Norway Norway
http://weblogs.asp.net/mnissen
http://www.puzzlepart.com

Comments and Discussions

 
GeneralBetter solutions than my original Article! Pin
Mads Nissen6-Aug-03 2:02
Mads Nissen6-Aug-03 2:02 
GeneralDynamicControlsPlaceholder Pin
Jeffry van de Vuurst6-Aug-03 1:29
Jeffry van de Vuurst6-Aug-03 1:29 
QuestionDatagrid? Pin
jpfouche27-Jun-03 5:01
jpfouche27-Jun-03 5:01 
AnswerRe: Datagrid? Pin
empire2924-Mar-06 10:44
empire2924-Mar-06 10:44 
QuestionDo this with a DataGrid with TextBox ItemTemplates? Pin
jpfouche27-Jun-03 2:10
jpfouche27-Jun-03 2:10 
QuestionWhy Store your counter in Special Page Class? Pin
jpfouche27-Jun-03 0:57
jpfouche27-Jun-03 0:57 
GeneralKind of convoluted Pin
MikeNewman27-Feb-03 15:26
MikeNewman27-Feb-03 15:26 
GeneralControl.CreateChildControls Pin
leppie19-Feb-03 6:23
leppie19-Feb-03 6:23 
Hi there

That is exactly why that method should be overridden! Eek! | :eek:

MSDN:

Notifies server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering.

You use this in combination with EnsureChildControls().

Cheers Smile | :)

[edit] found a useful snippet

protected override void CreateChildControls()
{
   //Child controls allways goes in here and we check with EnsureChildControls()
   TextBox text = new TextBox();
   text.Width = new Unit(400);
   text.Text = "I was created in Template";
   // we have to add to the Form MS seemed to get a bit DUMB here, will 99% be Controls[1]
   Controls[1].Controls.Add(text);
   Controls[1].Controls.Add( new LiteralControl("<br>"));

   //we decided to have our base controls included aswell
   base.CreateChildControls();
}


[edit]

MyDUMeter: a .NET DUMeter clone
"Thats like saying "hahahaha he doesnt know the difference between a cyberneticradioactivenuclothermolopticdimswitch and a biocontainingspherogramotron", but with words you have really never heard of."
GeneralRe: Control.CreateChildControls Pin
Helderix24-Nov-06 1:56
Helderix24-Nov-06 1:56 
GeneralPage_Init instead Pin
LukeDuff19-Feb-03 6:02
LukeDuff19-Feb-03 6:02 
GeneralRe: Page_Init instead Pin
gormer19-Mar-03 0:26
gormer19-Mar-03 0:26 
GeneralRe: Page_Init instead Pin
Anonymous26-Nov-03 21:25
Anonymous26-Nov-03 21:25 
GeneralRe: Page_Init instead Pin
diaphanein27-Apr-04 8:55
diaphanein27-Apr-04 8:55 
GeneralThis looks quite useful... Pin
Marc Clifton19-Feb-03 5:48
mvaMarc Clifton19-Feb-03 5:48 

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

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