Reputation: 934
I posted a question a couple of days ago about viewstate and after running some tests I have come to some conclusions/results. Based on these results I have a few questions as to how someone would do certain things.
Here are the results of my tests that I ran:
OnInit
of a Page, then his viewstate will be available in OnLoad
. All other controls that usercontrolA loads from it's OnInit
, will have their viewstate ready in their OnLoad
.OnLoad
of a Page, then his viewstate will be available in OnPreRender
. All other controls that usercontrolA loads from it's OnLoad
, will have their viewstate available in their OnPreRender
.OnLoad
and before OnPreRender
) of a Page, then his viewstate will not be available. All other controls that usercontrolA loades will not have their viewstate available.So in a perfect world you would always load all controls using situation #1, so that their viewstate is available on their OnLoad
. Unfortunately when you need to load a control from a button click or from a OnLoad
, is there no way for control to get its viewstate before OnPreRender
stage?
I have read a bunch of articles on viewstate and thought I understood it, but working on my current application which loads usercontrols which load other usercontrols, I am having a real hard time with being able to get viewstate on my leaf (last in the chain) usercontrol.
Any suggestions and/or links are appreciated.
Upvotes: 8
Views: 7985
Reputation: 85645
It is accepted practice to load dynamic controls in OnInit, so that they get the full control lifecycle. I'm not sure I particularly understand your situation though - if you're loading a control based on a button click, why would it have viewstate at that point? On the next OnInit, you should load the control again (I usually use a page level Viewstate item to track that a particular control needs to be loaded) so that it can restore from Viewstate. Something like:
class Default : Page {
enum LoadedControl { Textbox, Label, GridView }
override OnInit() {
if (IsPostback) {
var c = Viewstate["LoadedControl"] as LoadedControl;
if (c != null) LoadDynamicControl(c);
}
}
void Button_Click() {
var c = (LoadedControl)Enum.Parse(typeof(LoadedControl), ddl.SelectedValue);
LoadDynamicControl(c);
}
void LoadDynamicControl(LoadedControl c) {
switch (c) {
case LoadedControl.Textbox:
this.ph.Controls.Add(new Textbox());
break;
...
}
ViewState["LoadedControl"] = c;
}
}
The slightly more interesting bit, though, is that according to catch-up events - it really shouldn't matter. The callstack for dynamically loading a control looks something like:
Control.Controls.Add(Control)
Control.AddedControl(Control)
Control.LoadViewStateRecursive(object)
Control.LoadViewState(object)
Taking Label
as an example, it overrides LoadViewState
and pulls it's Text
property directly from ViewState. TextBox is similar. So, by my reading, it should be OK to add at any point, and then access ViewState. That doesn't seem to be jive with my experience, though, so further investigation seems warranted.
Upvotes: 3
Reputation: 3401
Did you try to use LoadComplete
event?
Use this event for tasks that require that all other controls on the page be loaded.
This is fired after PageLoad
and all events (ButtonClick, etc.), so your UserControls are are loaded in ButtonClick events, and in LoadComplete
their ViewState is already initialized.
Upvotes: 0
Reputation: 6277
I'm surprised but interested about your results. When I work with dynamic controls I always add them in Page_Init
. Anything else doesn't work. But you are right - how do you do it if you are adding them in response to a button click.
The only way I have found is by examining Request.Form("__EVENTTARGET")
collection at PageInit
. This contains the control ID of the control that has triggered the postback so for instance a button click. It will of course be qualified by the naming containers it appears in. Once you have identified the 'event' by this method you can add the controls you want.
It is of course all a bit hacky but it's the only way I found of doing these things. It does work.
It's interesting that the ViewState
is available on PreRender
if you add the controls at Page_Load
. But as the above link indicates it too late to help you then. The controls state is rehydrated during the load cycle. If it's not there then your control state or dynamic controls are just going to disappear.
Upvotes: 1
Reputation: 11341
I don't think I can add anything that this article doesn't cover.
Look specifically at the Life Cycle Events section.
http://msdn.microsoft.com/en-us/library/ie/ms178472.aspx
Upvotes: 4