【问题标题】:What do you do when you can't use ViewState?不能使用 ViewState 时怎么办?
【发布时间】:2010-09-07 21:26:45
【问题描述】:

我有一个相当复杂的页面,它在转发器内动态构建用户控件。在初始化 ViewState 之前,必须在 Init 页面事件期间绑定此转发器,否则动态创建的用户控件将不会保留其状态。

这创建了一个有趣的 Catch-22,因为我将转发器绑定到的对象需要在初始页面加载时创建,然后保留在内存中,直到用户选择离开或保存。

因为我不能使用ViewState 来存储这个对象,但在初始化期间它是可用的,我不得不将它存储在 Session 中。

这也有问题,因为我必须在非回发期间显式地将会话值设为空,以模拟 ViewState 的工作方式。

在这种情况下,必须有更好的状态管理方法。有什么想法吗?

编辑:一些关于使用 LoadViewState 的好建议,但我仍然遇到状态未恢复的问题。

这里有点像页面结构

页面 --> 用户控件 --> 中继器 --> 动态创建 N 个用户控件。

我将覆盖的LoadViewState 放在父UserControl 中,因为它被设计为完全封装并且独立于它所在的页面。我想知道这是否是问题所在。

【问题讨论】:

    标签: asp.net webforms viewstate page-lifecycle


    【解决方案1】:

    这也有问题,因为我必须在非回发期间显式地将会话值设为空,以模拟 ViewState 的工作方式。

    为什么您必须显式地清空该值(除了内存管理等)?检查 Page.IsPostback 是否不是一个选项,或者对 Session 变量做些什么?

    【讨论】:

      【解决方案2】:

      我总是在 LoadViewState 事件中重新创建我的动态控件。您可以将需要创建的控件数量存储在视图状态中,然后使用 LoadViewState 事件中的 LoadControl 方法动态创建其中的许多控件。在这种情况下,您可以访问 ViewState,但它尚未恢复到页面上的控件。

      【讨论】:

        【解决方案3】:

        1) 可能有一种方法可以让它工作...您只需要确保在正确的时刻将控件添加到树中。太快了,你不会得到 ViewState。太晚了,你没有得到 ViewState。

        2)如果你想不通,也许你可以关闭洞页的视图状态,然后只依赖查询字符串来改变状态?以前是回发的任何链接都将是指向另一个 URL(或回发重定向)的链接。

        这确实可以减轻页面的重量,并且更容易避免 ViewState 出现问题。

        【讨论】:

          【解决方案4】:
          protected override void LoadViewState(object savedState)
          {
             // Put your code here before base is called
             base.LoadViewState(savedState);
          }
          

          这是你的意思吗?或者您的意思是按什么顺序处理控件?我认为答案是准随机的。

          另外,为什么不能加载在 Page_Load 之前绑定的对象?如果需要,可以在页面生命周期中的任何时间调用您的业务层,但预渲染和之后的任何操作除外。

          【讨论】:

            【解决方案5】:

            我必须明确地使会话无效 非回发期间的价值,以便 模拟 ViewState 的工作原理。

            我仍然对为什么不能存储会话中绑定的任何对象感到困惑。如果您可以将该对象存储在会话中,则以下内容应该可以工作:

            1. 在首次加载时,在 OnPreInit 期间将您的顶级用户控件绑定到对象。将对象存储在会话中。 Viewstate 将自动为这些控件存储。如果您必须第一次在 Page_Load 上绑定控件,那没关系,但如果您按照下一步操作,最终将有两个调用 bind 的事件。
            2. 在回发时,将 OnPreInit 方法中的顶级用户控件与存储在会话中的对象重新绑定。您的所有控件都应在视图状态加载之前重新创建。然后,当视图状态恢复时,值将设置为视图状态中的任何值。这里唯一需要注意的是,当您在回发中再次绑定时,您必须 100% 确保再次创建相同数量的控件。使用带有动态控件的中继器、网格视图等的关键是,在加载视图状态之前,它们必须在每次回发时反弹。 OnPreInit 通常是执行此操作的最佳位置。框架中没有技术限制规定您必须在第一次加载时在 Page_Load 中完成所有工作。

            这应该可行。但是,如果由于某种原因不能使用 session,那么您将不得不采取稍微不同的方法,例如在绑定控件后将绑定的任何内容存储在数据库中,然后将其从数据库中拉出并重新绑定在每次回发时再次。

            我是否遗漏了有关您的情况的一些明显细节?我知道在不发布代码的情况下解释情况的微妙之处可能非常棘手。

            编辑:我在此解决方案中将所有对 OnInit 的引用更改为 OnPreInit。我忘记了 MS 在 ASP.NET 2.0 中引入了这个新事件。根据他们的page lifecycle documentation,OnPreInit 是应该创建/重新创建动态控件的地方。

            【讨论】:

              【解决方案6】:

              创建动态控件时...我只在初始加载时填充它们。后记我在页面加载事件中重新创建回发控件,并且视图状态似乎可以毫无问题地处理值的重新填充。

              【讨论】:

                【解决方案7】:

                页面上的LoadViewState方法绝对是答案。大致思路如下:

                protected override void LoadViewState( object savedState ) {
                  var savedStateArray = (object[])savedState;
                
                  // Get repeaterData from view state before the normal view state restoration occurs.
                  repeaterData = savedStateArray[ 0 ];
                
                  // Bind your repeater control to repeaterData here.
                
                  // Instruct ASP.NET to perform the normal restoration of view state.
                  // This will restore state to your dynamically created controls.
                  base.LoadViewState( savedStateArray[ 1 ] );
                }
                

                SaveViewState 需要创建我们上面使用的 savedState 数组:

                protected override object SaveViewState() {
                  var stateToSave = new List<object> { repeaterData, base.SaveViewState() };
                  return stateToSave.ToArray();
                }
                

                别忘了在 Init 或 Load 中也绑定中继器,使用如下代码:

                if( !IsPostBack ) {
                  // Bind your repeater here.
                }
                

                【讨论】:

                  猜你喜欢
                  • 2021-08-17
                  • 2013-05-27
                  • 1970-01-01
                  • 2014-06-17
                  • 1970-01-01
                  • 2011-11-07
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多