【问题标题】:Not understanding why ViewState is not increasing in size when changing content?不明白为什么 ViewState 在更改内容时没有增加大小?
【发布时间】:2011-06-04 11:09:57
【问题描述】:

我以为我理解 ViewState,但这有点奇怪。

我有一页有 1000 个标签和文本框,如下所示:

<dt>
   <asp:Label runat="server" ID="Label1" AssociatedControlID="TextBox1">Label1</asp:Label>
</dt>
<dd>
   <asp:TextBox runat="server" ID="TextBox1"></asp:TextBox>
</dd>

全部递增 1。我在顶部添加了一个按钮:

<asp:Button runat="server" ID="PostBack" Text="Post it all back!" OnClick="ChangeValues"/>

对应的代码是:

protected void ChangeValues(object sender, EventArgs e)
{
   for (int i = 1; i <= 1000; i++)
   {
      string textBoxId = "TextBox" + i;
      ((TextBox)Page.FindControl(textBoxId)).Text = textBoxId;
   }
}

所以我的理解是:

  1. 首次页面加载,控件最初设置,因此未创建控件视图状态
  2. 在回发时,单击按钮正在修改控件。因此,在生成 ViewState 时,.NET 会意识到文本已从默认值更改,并将其记录在视图状态中。

现在对于 1000 个控件,您会期望它相当大,比这大得多:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNjYzODc0MDE1ZGQRGHqYtZTbbkevIfg33I4Wja+xfz0at0+fDMS72BtZNA==" />

我想我在这里错过了一个技巧。我打开了Trace=true,并注意到所有的 ViewState 仍然是 0 字节。 EnableViewStateViewStateMode 未在 &lt;@Page 指令中声明,因此 ViewState 处于打开状态并正常工作。

谁能帮我理解为什么我会误解这是如何工作的?

【问题讨论】:

  • 我正在尝试了解您在网页上使用 1,000 多个控件可能会做什么。
  • 这只是一个极端的例子,如果你愿意,你可以将它减少到 50 - 或者 2。它仍然会发生。
  • 哇,听到这个我松了一口气。

标签: c# viewstate asp.net-4.0


【解决方案1】:

可能是因为 TextBox 的 Text 属性不需要保存到 ViewState 中,因为它会被渲染到页面并与发布数据一起回发。

如果你看一下 TextBox 与 Reflector 的实现,你会发现它有一个属性 SaveTextViewState 来控制是否需要将 Text 属性保存到 ViewState:

protected override object SaveViewState()
{
    if (!this.SaveTextViewState)
    {
        // This means the Text property will not be saved to ViewState
        this.ViewState.SetItemDirty("Text", false);
    }
    return base.SaveViewState();
}

在需要保存 ViewState 的情况下(例如 TextBox 不可见),SaveTextViewState 返回 true 并将 Text 属性保存到 ViewState。

更新

根据Reflector实现SaveTextViewState属性(用于判断Text是否需要持久化到ViewState的属性)如下:

private bool SaveTextViewState
{
    get
        {
            if (this.TextMode == TextBoxMode.Password) return false;
        }
        if (((base.Events[EventTextChanged] == null) && 
              base.IsEnabled) && 
              ((this.Visible && !this.ReadOnly)  && 
              (base.GetType() == typeof(TextBox))))
        {
            return false;
        }
        return true;
    }
}

即如果Text 不是密码文本框并且以下任何一项为真,则将其持久化到 ViewState:

  • 存在 TextChanged 事件的处理程序(在这种情况下,它需要原始值来检测文本是否已更改)

  • 控件被禁用(在这种情况下文本不会被回发)

  • 控件不可见(在这种情况下不会呈现)

  • 控件是只读的(文本不会回发)

  • 控件类型不是TextBox(不要通过抑制 ViewState 进行优化,因为这可能会影响派生控件的实现)。

本质上是一种优化,如果确定不需要 ViewState,它会抑制它。

【讨论】:

  • 我希望它在 ViewState 中,因为它在 LoadPostbackData() 和 SavePostBackData() 之间发生了变化。虽然 Request.Form 有信息,但它如何确定下一次内容是否发生了变化?
  • 感谢乔,您的更新解释对您有所帮助。我相信,由于我没有明确寻找更改的事件,因此 API 不会通过不将更改存储在 ViewState 中来通知我更改。
【解决方案2】:

答案是实现IPostBackEventHandler 的控件如Textbox, Checkbox 等将保留状态even after disabling the viewstate。原因是在 Load Postback Data 阶段,这些控件会从 Posted back 表单中获取状态信息。

但是像 label 这样没有实现 IPostBackEventHandler 的控件不会从回发的数据中获取任何状态信息,因此完全依赖 viewstate 来维护状态。

【讨论】:

  • 我可以理解为什么 Label 文本不在 ViewState 中,因为它与最初呈现的内容没有变化。但是,如果您比较 TextBox 项目 - 在初始化时它是空白的。在传输给用户时,它具有从原始空白状态修改的内容。为了确定一个 OnTextChanged 事件,它必须能够将发送给用户(来自 ViewState)的数据与下一个发布的(Request.Form)值进行比较?
  • @Dominic - “为了确定一个 OnTextChanged 事件,它必须能够比较发送给用户的数据(来自 ViewState)” - 如果你有一个 TextChanged 事件处理程序,它将持久化ViewState 的文本属性。请参阅我的更新答案。
猜你喜欢
  • 2012-07-31
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2013-01-25
  • 2017-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多