Peter's Gekko

Sponsors

The Lounge

Wicked Cool Jobs

News

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Adding controls at runtime, the viewstate and the page lifecycle

In yesterday's post I blogged  about problems with the viewstate after adding a control at runtime. A great thing with blogging are the responses, one by Martijn Boland inspired me to a more systematic investigation of the problem.

As a test bed I take a simple web form. It has one label, one textbox, a button, a checkbox and a panel. On creation I will add another textbox and another label from code. These controls are declared as privates in the code behind and they do not appear in the html of the aspx page. This dynamic addition is done twice, once in the OnInit event and once in the Page_Load.

private Label Label2;
private Label Label3;

private TextBox TextBox2;
private TextBox TextBox3;

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
    Label2 = new Label();
    this.Controls.Add(Label2);
    TextBox2 = new TextBox();
    Panel1.Controls.Add(TextBox2);

    InitializeComponent();
    base.OnInit(e);
}

private void InitializeComponent()
{
....
}
#endregion

private void Page_Load(object sender, System.EventArgs e)
{
    Label3 = new Label();
    this.Controls.Add(Label3);
    TextBox3 = new TextBox();
    Panel1.Controls.Add(TextBox3);
}


Trying to add a textbox to the controls collection of the page itself will result in an error :  Control '_ctl1' of type 'TextBox' must be placed inside a form tag with runat=server. Textboxes need a container control. Adding them to an existing panel will do.
Whether the viewstate of the dynamically created textboxes is working is easy to see. To test the viewstate of the labels I use the checkbox to conditionally update their text. This is done in the PreRender event.

private void WebForm1_PreRender(object sender, System.EventArgs e)
{
    if (CheckBox1.Checked)
    {
        Label1.Text = TextBox1.Text;
        Label2.Text = TextBox2.Text;
        Label3.Text = TextBox3.Text;
    }
}

What the demo will show is that the viewstate of all three control pairs, created in the designer, in the onInit and in the page_load does work. The contents and caption are preserved over roundtrips. This is actually what I did expect from the viewstate. As it has such a nice programming interface I expected the same flexible behaviour when adding controls. Nevertheless I ran into trouble with the viewstate when adding a literal control in the base webform of my app. The behaviour of the app became quite erratic and all debugging pointed to a wrecked viewstate. Martijn pointed me to the fact that it matters at which moment in the page lifecycle you add your control.  I had done it in the page_load, moving the code to the OnInt fixed this. A closer look at the page life cycle made clear why this can make a difference.

The life cycle of a page goes through these steps

  1. Construct page
  2. Initialize (OnInit)
  3. Begin tracking Viewstate
  4. Load (Page_load)
  5. Prerender (OnPreRender)
  6. Save View state
  7. Render
  8. UnLoad (OnUnload)

You can hook in your own code using Onxxx events. To hook into other events you have to override the corresponding method. As you see the tracking of changes starts after the OnInit event. Anything done after that will interfere with maintaining the state. And can (as in my app) but will not always (as in the demo presented) wreck the state.

Peter

 


Posted Tue, Feb 3 2004 7:54 AM by pvanooijen

[Advertisement]

Comments

Mindy wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Sat, Feb 21 2004 3:06 PM
I'm new to ASP.NET and C#. Your post was really helpful to me, especially the life cyle of a page. I was wondering if you could take this a step further and somehow avoid the 'private Label label2;' declaration. I'm seeking to have another dropdownlist generated after the onchange method of another dropdown...actually a series of this effect. So is it necessary to have every control I plan to create programatically already declared?
Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Sun, Feb 22 2004 1:23 PM
When and how you the declare your controls is up to you. My only point is the moment the dynamically created control is inserted into the control tree.
Jason wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Fri, Mar 26 2004 5:20 PM
I have the same question as Mindy.
In your example you already know how many textboxes and labels you wanted to add dynamically and so you could easily declare

private TextBox TextBox2;
private TextBox TextBox3;

I am developing an application in which I do not know how many textboxes, labels and Dropdownlists I need before-hand. I retreive certain records from the database and if i retrieve N records I create N textboxes, labels and Dropdownlists. So far so good,

The problem lies in the fact that I cannot add this information in the OnInit Function (because I simply do not know how many controls I will need).

When the user selects values from N dynamically
dropdownlists and textboxes, my submit_click event needs to get these selected values.

I would appreciate any help in this regard,
-Jason-




Peter's Gekko wrote Why Page_load ?
on Sun, Mar 28 2004 7:19 AM
Why Page_load ?
Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Sun, Mar 28 2004 12:18 PM
Jason,

I would use the datalist to get your thing done. There is an itemtemplate for every row in your db.

Personnaly I add as many controls as possible at design time. When the control is not needed I can set its visible property to false. Invisible controls are not rendered to the response, they have no overhead for the client. The visible property is bindable, so you can set it from code depending on anything you can imagine.

The items in the list can be read from code. In case you want to read nore check some of my latest articles on the dnj.

http://www.dotnetjunkies.com/Tutorial/4D57511C-653C-406C-B5ED-B364640DAF2F.dcik
Peter
DLARLICK wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, Mar 29 2004 12:24 PM

Hmm,

I liked the example but have a slight variation.

I am attempting a menu, witch works fine (dynamic by role of user) Loaded at OnInit. However a menu selection runs a delegate. This delegate would then attempt to load the appropriate control into the body of the aspx form.

The delegate runs after the page load and attempts to load the appropriate control. At this time the app does not maintain viewstate for the dynamically generated control.

The only option that I have figured to work is to use a querystring and parse in the OnInit or PageLoad. Using a querystring is undesireable due to user ability to request controls through the URL.

I have played with using the ViewState explicitly, but am missing something that is done by default when instantiated in the appropriate startup method.

I would appreciate any comment.

Thanks!


Peter's Gekko wrote Adding a control a runtime : what is not in the viewstate
on Mon, Mar 29 2004 7:15 PM
Adding a control a runtime : what is not in the viewstate
Alicia wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Fri, May 7 2004 1:42 PM
Hi!

I also have a small variation of the problem - I read from the database how many controls I need, but I have to provide the user with the ability to change the number at runtime. So imagine this: I have a page, with 2 distinct areas (one is the general info, one is the number of levels). Let's say initially I have 2 levels, that's 2 sets of controls (3 textBoxes per level). Now the user say 4 instead of 2 - I need to refresh the page and have 2 more sets of controls added. How do I do this so I won't loose the data in the first area (which might have been already modified by the user)?

I tried to add some functionality in the onTextChanged method, but adding the controls don't appear on the screan... How do I force the page to "repaint" that area?

I would appreciate any ideas - Thanks!
Alicia
Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, May 10 2004 6:40 AM
hi Alicia,
the ontextchanged event is far to late to add anything on the same roundtrip.

What I would do is create all controls at designtime, perhaps in a list or repeater, and set the visibility of the controls in a databinding expression.

Does that help ?
Peter
Alicia wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, May 10 2004 9:07 AM
Hi Peter,

Yes, I understand that the event is way to late, my problem is I have no idea how many controls to define in advance! Other than set a maximum (which is good enough probbaly in this case), which cannot be changed other than re-deploying the application...

My question was if it's possible to somehow re-post only a part of the page - I would not use the ontextchanged event, but a button... but I don't want to re-post the whole page (I don't want to loose the other settings the user might already have changed).

I can workaround with setting some rules for the end user, but I'd like to know if something like that it's possible.

TIA,
Alicia
Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, May 10 2004 9:39 AM
Hi,

You cannot postback a part of the page yet, you can in .NET 2. There's a good article on that on the junkies : http://www.dotnetjunkies.com/Tutorial/E80EC96F-1C32-4855-85AE-9E30EECF13D7.dcik

I would go for a datlist or repeater. Never mind the full postback, the viewstate should take care of all settings allready entered.
Alicia wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, May 10 2004 10:22 AM
I'll use a repeater then :-)

Thanks,
Alicia
xxxxxxx wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Wed, Jul 14 2004 9:12 AM

Can find users data entry before init if you have registered post back or not.
Just use Page.Request.Form

// Page.Request.Form
// [3] "_ctl0:_ctl0:_ctl0:_ctl1:_ctl6:_ctl0"
// [4] "_ctl0:_ctl0:_ctl1:_ctl1"
// [5] "_ctl0:_ctl0:_ctl2:_ctl1"
//
// ID "_ctl0:_ctl1"
// ClientID "_ctl0__ctl0__ctl1"
// UniqueID "_ctl0:_ctl0:_ctl1"
//
// Looking for "_ctl0:_ctl0:_ctl1:_ctl1" this control plus the control id withing this control

[Conditional("DEBUG")]
public void IterateThroughForm()
{
String m_strlastErr = String.Empty;
ArrayList indices = null;
ArrayList state = null;

try
{
if ((this.Page.Request.Form == null) || (this.Page.Request.Form.Count <= 0))
return;

indices = new ArrayList();
state = new ArrayList();

// Only occurs if control registered as post back will have __EVENTTARGET
string t_strTarget = Page.Request.Form["__EVENTTARGET"];
string t_strValue = Page.Request.Form["__EVENTARGUMENT"];

// [0] "__EVENTTARGET" _ctl0:_ctl0:_ctl1

foreach (string cName in Page.Request.Form.Keys)
{
if ((cName == null) || (cName.Length <= 0))
continue; // cName "_ctl0:_ctl0:_ctl0:_ctl1"

if ( cName.IndexOf("__VIEWSTATE") != -1 )
continue;

if (Page.Request.Form[cName] == null)
continue;

m_strlastErr += String.Format(" Key {0} Values " , cName);

String [] l_astrValues = Page.Request.Form.GetValues(cName);

if ((l_astrValues == null) || (l_astrValues.GetLength(0) <= 0))
continue;

foreach (String cValue in l_astrValues)
{
if ( ( cValue == null ) || (cValue.Length <= 0))
continue;

m_strlastErr += String.Format(" {0} " , cValue);

}
}
}
catch (Exception ex)
{
m_strlastErr = ex.Message;
}

HttpContext.Current.Trace.Write("Info", m_strlastErr);
} // IterateThroughForm


[Conditional("DEBUG")]
public void IterateThroughPostBack(NameValueCollection postCollection)
{
String m_strlastErr = String.Empty;

try
{
if ( (postCollection == null) || (postCollection.Count <= 0))
return;

foreach (String cName in postCollection.Keys)
{
if ( ( cName == null ) || (cName.Length <= 0))
continue;
if ( ( cName.IndexOf("__EVENTTARGET") != -1 ) ||
( cName.IndexOf("__EVENTARGUMENT") != -1 ) ||
( cName.IndexOf("__VIEWSTATE") != -1 ) )
continue;

// [0] "__EVENTTARGET" "" nothing
// [1] "__EVENTARGUMENT" "" nothing
// [2] "__VIEWSTATE" "kdlfjgkldsjgriogjbkjk" lot of encrypted stuff
//
// "_ctl0:_ctl0:_ctl1:_ctl1" "3333" - new value in control
// "_ctl0:_ctl0:_ctl2:_ctl1" "extered text"

m_strlastErr += String.Format(" Key {0} Values " , cName);

String [] l_astrValues = postCollection.GetValues(cName);

if ((l_astrValues == null) || (l_astrValues.GetLength(0) <= 0))
continue;

foreach (String cValue in l_astrValues)
{
if ( ( cValue == null ) || (cValue.Length <= 0))
continue;

m_strlastErr += String.Format(" {0} " , cValue);

}
}
}
catch (Exception ex)
{
m_strlastErr = ex.Message;
}

HttpContext.Current.Trace.Write("Info", m_strlastErr);
} // IterateThroughPostBack

Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Wed, Jul 14 2004 10:14 AM
mmm, could you provide some comments ?
KaaN wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Thu, Sep 30 2004 10:04 AM
Hi xxxxxxxxxxx,

I believe, that you are trying to help us, but I didn't understand what you do there. Can you please give some explanation?

KaaN
Chuttad wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Sun, Nov 21 2004 11:53 PM
Bhenchod
Chuttad wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Sun, Nov 21 2004 11:53 PM
Bhenchod
Peter van Ooijen wrote re: Adding controls at runtime, the viewstate and the page lifecycle
on Mon, Jan 31 2005 7:27 AM
I see two problems
- You are adding the controls at a pretty late moment in the page's lifecycle.
- Controls addded to the templates of a datalist will never appear in the main Controls collection of the Page.

In your case I would consider adding the controls at design time and setting its visibility using some (fancy ?) binding expression.
Peter's Gekko wrote Adding a control a runtime : what is not in the viewstate
on Thu, Jul 6 2006 4:35 PM
In several earlier post on adding controls at runtime and the potential impact on the viewstate I could...

Add a Comment

(required)  
(optional)
(required)  
Remember Me?
Devlicio.us