回发时,Viewstate为null

时间:2011-12-02 11:17:48

标签: c# asp.net webforms

是的,我在这里有一些非常特别的东西......

带有以下属性的ASP.NET 4页面:

protected QuickShopBag QuickShopBagInstance
{
    get { return (QuickShopBag)ViewState["QuickShopBag"]; }
    set { ViewState["QuickShopBag"] = value; }
}

在最初Page_Load()!Page.IsPostBack)期间,QuickShopBagInstance已填充并ViewState已保存。

但是当您在页面上执行回发时,从回发Button_OnClick()事件访问时ViewState为空!!!

我已经检查了Request.Form,确定_Viewstate值已存在且已填充。我还通过解析器运行了这个值,它确实包含了预期的数据,页面包含ViewStateEnabled="true"和新的.NET 4 ViewStateMode="Enabled"

我已经继续覆盖LoadViewState方法以检查它是否正在触发,它似乎不是。

protected override void LoadViewState(object savedState)
{
    base.LoadViewState(savedState);
}

我真的很遗憾可能是什么问题。有什么想法吗?

4 个答案:

答案 0 :(得分:9)

首先我错了,有问题的代码不是在Page_Load中,而是在Page_Init中,虽然我没有读过任何说明你无法在Init分配给ViewState的内容。

所以我整理了一个非常基本的测试,复制了我遇到的问题......

<form id="form1" runat="server">
<div>
    <asp:ListView id="QuickshopListView" runat="server">
        <LayoutTemplate>
            <asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
        </LayoutTemplate>
        <ItemTemplate>
            <asp:TextBox ID="txtItem" runat="server" Text='<%# Container.DataItem %>' />
            <asp:Button ID="btnDelete" runat="server" Text="Delete" OnClick="btnDelete_Click" />
            <br />
        </ItemTemplate>
    </asp:ListView>
    <asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
</div>
</form>

public partial class Quickshop : System.Web.UI.Page
{
    protected QuickShopBag QuickShopBagInstance
    {
        get { return (QuickShopBag)ViewState["QuickShopBag"]; }
        set { ViewState["QuickShopBag"] = value; }
    }

    protected void Page_Init(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            if (QuickShopBagInstance == null)
                QuickShopBagInstance = new QuickShopBag();

            if (!String.IsNullOrEmpty(Request.QueryString.ToString()))
            {
                string[] items = Server.UrlDecode(Request.QueryString.ToString()).Split(',');
                if (items.Length > 0)
                {
                    foreach (string item in items)
                    {
                        QuickShopBagInstance.QuickShopItems.Add(item);
                    }
                }
            }
        }
    }

    protected void Page_LoadComplete(object sender, EventArgs e)
    {
        QuickshopListView.DataSource = QuickShopBagInstance.QuickShopItems;
        QuickshopListView.DataBind();
    }

    protected void btnAdd_Click(object sender, EventArgs e)
    {
        if (QuickShopBagInstance == null)
            QuickShopBagInstance = new QuickShopBag();

        QuickShopBagInstance.QuickShopItems.Add("add1");
        QuickShopBagInstance.QuickShopItems.Add("add2");
        QuickShopBagInstance.QuickShopItems.Add("add3");
    }

    protected void btnDelete_Click(object sender, EventArgs e)
    {
        Button DeleteButton = (Button)sender;
        ListViewDataItem item = (ListViewDataItem)DeleteButton.NamingContainer;
        QuickShopBagInstance.QuickShopItems.RemoveAt(item.DisplayIndex);
    }
}

[Serializable]
public class QuickShopBag
{
    public List<string> QuickShopItems { get; set; }

    public QuickShopBag()
    {
        this.QuickShopItems = new List<string>();
    }
}

如果您请求说“/quickshop.aspx?add1,add2,add3”,则使用来自qs的数据正确填充ListView,但是当单击删除按钮时会抛出NullReferenceException,因为ViewState没有' t持有QuickShopBag对象。

但是,如果您单击“添加”按钮,您可以看到它向QuickShopBagInstance(和ViewState)添加相同的值,ListView将正确填充,当您单击“删除”按钮时,它可以完美地运行,因为ViewState具有一直坚持。

现在,如果您将查询字符串位读取更改为Page_InitComplete而不是Page_Init,则它可以完美地运行。所以结论是......

您无法在Init_Complete之前添加到视图中!!!!!!!!

我是多么愚蠢,至少是谁写的呢!

答案 1 :(得分:1)

到目前为止,您似乎排除了大部分建议,因此我创建了一个基本页面,其中只包含您上面提供的信息:

namespace SO_Questions
{
    [Serializable()]
    public class QuickShopBag
    {
        public string MyProperty { get; set; }
    }
}

背后的代码

namespace SO_Questions
{
    public partial class TestPage : System.Web.UI.Page
    {
        protected QuickShopBag QuickShopBagInstance
        {
            get { return (QuickShopBag)ViewState["QuickShopBag"]; }
            set { ViewState["QuickShopBag"] = value; }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                this.QuickShopBagInstance = new QuickShopBag() { MyProperty = "Test String" };
            }
            Message.Text = "Value is: " + this.QuickShopBagInstance.MyProperty.ToString();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            btnSubmit.Text += QuickShopBagInstance.MyProperty;
        }
    }
}

标记:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestPage.aspx.cs" Inherits="SO_Questions.TestPage" ViewStateMode="Enabled" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server"><title></title></head>
<body>
    <form id="form1" runat="server"><div>
        <asp:Label ID="Message" runat="server"></asp:Label>
        <asp:Button runat="server" ID="btnSubmit" Text="Submit" OnClick="btnSubmit_Click" />
    </div></form>
</body></html>

正如所料,这运行正常;命中重写的LoadViewState方法(并且viewstate正确包含2个项目)并更新按钮的文本。

合乎逻辑的解释是,其他地方还会发生其他事情,或者您未能提供额外的重要信息。

答案 2 :(得分:0)

过去让我绊倒的是

  1. 在页面的ViewState中设置内容
  2. 然后尝试在用户控件中检索它。找不到它 - 哪里去了?
  3. 似乎每页应该有一个ViewState,但每个用户控件都保留了它自己的版本。

    可能是这样的吗?

    这个SO link给出了我刚刚完成的更好的解释

答案 3 :(得分:0)

快速记下。如果要在page_load上设置ViewState值,请确保将其包装在

if (!IsPostBack)
{

ViewState["MyValue"] = MyValue // set dynamically with appropriate code

}

如果您不执行此操作而执行了回发操作...但是在!IsPostBack括号中将此ViewState值设置为 not 的代码,它将每次将ViewState值重置为null无论您在页面上的何处启用ViewState,都可以进行回发。

这看起来似乎很明显,但是如果您正在执行大量代码,则很容易错过。

或者,如果您希望代码在每次回发中运行,我想您不能使用!IsPostBack。但是,如果在回发时将值设置为null遇到麻烦,请仔细检查以上内容。