2012-02-01 64 views
8

我几天前发布了一个关于viewstate的问题,并在运行一些测试后得出了一些结论/结果。基于这些结果,我有几个问题,如何有人会做某些事情。Viewstate和控件在ASP.NET

这里是我的测试,我跑了结果:

  1. 如果usercontrolA从页面的加载OnInit,那么他的视图状态将在OnLoad可用。 usercontrolA从OnInit加载的所有其他控件将在OnLoad的视图状态中准备好。
  2. 如果从页面的OnLoad加载usercontrolA,则其视图状态将在OnPreRender中可用。 usercontrolA从OnLoad加载的所有其他控件将在其OnPreRender中提供其查看状态。
  3. 如果usercontrolA是从一个页面的事件(例如:按钮单击事件在OnLoad之前和OnPreRender之前触发)加载的,则其视图状态将不可用。 usercontrolA loades的所有其他控件都没有可用的viewstate。

因此,在一个完美的世界中,您将始终使用情景#1加载所有控件,以便他们的查看状态可用于其OnLoad。不幸的是,当您需要从按钮点击或从OnLoad加载控件时,控件在OnPreRender阶段之前没有办法获取其视图状态?

我已经阅读了一堆关于viewstate的文章,并认为我理解它,但在加载其他usercontrols的用户控件的当前应用程序上工作时,我真的很难获得viewstate在我的叶子上最后在链中)usercontrol。

任何建议和/或链接表示赞赏。

回答

3

在OnInit中加载动态控件是公认的做法,以便它们获得完整的控件生命周期。我不确定我是否特别了解你的情况 - 如果你是通过点击按钮加载控件,为什么它会在这个时候具有视图状态?在接下来的的OnInit,你应该再次载入控制(我通常使用一个页面级视图状态的项目跟踪一个特定的控制需要加载),以便它可以从恢复的Viewstate。例如:

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; 
    } 
} 

然而,稍微有趣一点的是,根据追赶事件 - 它确实不重要。对于动态加载控件调用堆栈看起来类似:

Control.Controls.Add(Control) 
    Control.AddedControl(Control) 
     Control.LoadViewStateRecursive(object) 
      Control.LoadViewState(object) 

Label为例,它覆盖LoadViewState和拉它Text财产直接从ViewState中。 TextBox是相似的。所以,通过我的阅读,应该可以在任何时候添加,然后访问ViewState。尽管如此,我的经验似乎没有变化,所以进一步的调查似乎是有必要的。

+0

嗨,这是我为什么试图使用viewstate的问题之一。我需要以某种方式标记我的控件在上一回发中的onclick处理程序加载后需要在下一个回传中加载。我正在考虑使用页面中的视图状态来获取值。在我的测试中,似乎这可能是要走的路。 – BlueChameleon 2012-02-01 17:51:35

1

我很惊讶,但对您的结果感兴趣。当我使用动态控件时,我总是将它们添加到Page_Init中。别的什么都行不通。但是你是对的 - 如果你为响应点击按钮而添加它们,你怎么做。

我发现的唯一方法是通过检查Request.Form("__EVENTTARGET")收集在PageInit。这包含触发回发的控件的控件ID,例如点击按钮。当然,它会通过出现的命名容器进行限定。一旦通过此方法识别了“事件”,您可以添加所需的控件。

这当然都有点冒失,但这是我发现做这些事情的唯一途径。它确实有效。

如果您在Page_Load处添加控件,有趣的是ViewState可用于PreRender。但是,正如上面的链接表明它为时太晚,以帮助你。控制状态在加载循环期间被重新水化。如果它不存在,那么你的控制状态或动态控制就会消失。

+0

我认为他没有区分Viewstate可用并在回发之间持续存在。 ViewState在Page.Load期间从以前的回发中加载,这意味着如果您在Page.Load处理程序期间创建控件,它将错过其视图状态自动保持。 – pseudocoder 2012-02-01 17:02:33

0

您是否尝试使用LoadComplete事件?

将此事件用于需要加载页面上所有其他控件的任务。

这之后PageLoad和所有事件(ButtonClick等)发射,所以你的用户控件在ButtonClick事件被加载,并在其LoadComplete的ViewState已初始化。

+0

感谢您的回复,但我不确定我在追随。其中一个用户控件需要从它的视图状态中获取一个值。 LoadComplete处于页面级别。 – BlueChameleon 2012-02-01 17:06:13

+0

如果您想要知道发生了哪些点击事件的事件,则首先使用LoadComplete。 – Leon 2012-02-01 18:33:35