Viewstate and controls in ASP.NET

2020-06-03 07:06发布

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:

  1. If usercontrolA is loaded from 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.
  2. If usercontrolA is loaded from 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.
  3. If usercontrolA is loaded from an event (Example: button click. Events fire after 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.

4条回答
SAY GOODBYE
2楼-- · 2020-06-03 07:52

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.

查看更多
别忘想泡老子
3楼-- · 2020-06-03 07:58

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

查看更多
Bombasti
4楼-- · 2020-06-03 07:58

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.

查看更多
看我几分像从前
5楼-- · 2020-06-03 07:59

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.

查看更多
登录 后发表回答