页面生命周期中的.net ViewState

时间:2010-03-31 17:39:45

标签: c# .net viewstate lifecycle pageload

我有一个包含名为PhoneInfo.ascx的控件的页面。使用LoadControl()动态创建PhoneInfo,然后调用initControl()函数传入初始化对象,以在PhoneInfo中设置一些初始文本框值。

用户然后更改这些值并点击页面上的提交按钮,该按钮连接到“submit_click”事件。此事件调用PhoneInfo中的GetPhone()函数。返回值包含所有新用户输入的值,但phoneId值(存储在ViewState中且未由用户编辑)始终返回为null。

我认为viewstate负责跟踪用户在回发中输入的数据,所以我无法理解用户值是如何回来的,而不是明确设置的ViewState [“PhoneId”]值!如果我在PhoneInfo的page_load事件中设置ViewState [“PhoneId”]值,它会在回发后正确检索它,但这不是一个选项,因为我只能在页面准备好提供它时初始化该值。

我确定我只是在某种程度上弄乱了页面生命周期,任何建议或问题都会有所帮助!我在下面列出了实际代码的简化版本。

包含网页的代码隐藏

protected void Page_Load(object sender, EventArgs e)
{
    Phone phone = controlToBind as Phone;
    PhoneInfo phoneInfo = (PhoneInfo)LoadControl("phoneInfo.ascx"); //Create phoneInfo control
    phoneInfo.InitControl(phone); //use controlToBind to initialize the new control
    Controls.Add(phoneInfo);
}
protected void submit_click(object sender, EventArgs e)
{
    Phone phone = phoneInfo.GetPhone();
}

PhoneInfo.ascx codebehind

protected void Page_Load(object sender, EventArgs e)
{
}

public void InitControl(Phone phone)
{
    if (phone != null)
    {
        ViewState["PhoneId"] = phone.Id;
        txt_areaCode.Text = SafeConvert.ToString(phone.AreaCode);
        txt_number.Text =  SafeConvert.ToString(phone.Number);
        ddl_type.SelectedValue = SafeConvert.ToString((int)phone.Type);
    }
}

public Phone GetPhone()
{
    Phone phone = new Phone();
    if ((int)ViewState["PhoneId"] >= 0)
        phone.Id = (int)ViewState["PhoneId"];
        phone.AreaCode = SafeConvert.ToInt(txt_areaCode.Text);
        phone.Number = SafeConvert.ToInt(txt_number.Text);
        phone.Type = (PhoneType)Enum.ToObject(typeof(PhoneType),       SafeConvert.ToInt(ddl_type.SelectedValue));
        return phone;
    }
}

4 个答案:

答案 0 :(得分:1)

我和回答者一样,认为这个问题存在是因为我设置的ViewState变量太晚而无法在SaveViewState期间保存。但是,我为SaveViewState事件添加了一个覆盖,并且我确实在保存ViewState之前很久就设置了我的ViewState变量。事实证明,太久了。

显然在初始化之后,.net运行TrackViewState(),它实际上开始监听你添加的任何viewState变量。因为我在运行TrackViewState()之前设置了这个viewState值,所以一切都很好但是在SaveViewState期间实际上没有添加这些值。我在设置变量之前就明确调用了TrackViewState(),一切都按预期工作。

我的最终解决方案是通过初始化分配一个私有属性来保存ID值,然后从属性值中设置SaveViewState期间的viewState变量。通过这种方式,我可以确保TrackViewState已经由.net运行,而无需显式调用它并搞乱事物流。我在page_load上重新加载viewState值并使用它来设置我可以在我的GetPhone函数中使用的属性值。

这个article讨论了enableViewState。

private int _id = -1;

protected void Page_Load(object sender, EventArgs e)
{
    if (ViewState["PhoneId"] != null)
    _id = SafeConvert.ToInt(ViewState["PhoneId"]);
}

protected override object SaveViewState()
{
    ViewState["PhoneId"] = _id;
    return base.SaveViewState();
}

public Phone GetPhone()
{
    Phone phone = new Phone();
    phone.Id = _id;
    phone.AreaCode = SafeConvert.ToInt(txt_areaCode.Text);
    phone.Number = SafeConvert.ToInt(txt_number.Text);
    return phone;
}

答案 1 :(得分:0)

ViewState在Init和Load事件之间进行管理。当你担心从回发中维护值时,你应该使用从Page_Init处理程序而不是Page_Load调用的代码或函数。

有关ASP.NET页面生命周期的更多信息,请参阅此链接。

http://msdn.microsoft.com/en-us/library/ms178472.aspx

答案 2 :(得分:0)

要完成你正在做的事情,你必须在页面生命周期的Init部分加载控件。

但是,要更轻松地执行此操作,为什么不将其添加到<asp:ContentPlaceHolder>?我认为这将使这更容易。

答案 3 :(得分:0)

根据评论回复,我在这里添加了另一个答案,解释了页面生命周期的一部分以及它对发布和查看状态数据的意义。下面是一个更加英语(对开发),更少关于页面生命周期开始的事件版本:

  1. 用户请求页面(请求1)
  2. ASP.NET使用字段(请求1)
  3. 中的默认值构建页面
  4. 在Page_Load上,使用默认值(请求1)
  5. 添加此特殊控件
  6. 您将此页面发送给用户(请求1)
  7. 用户将数据发布到页面(请求2)
  8. ASP.NET从您的ASPX文件(请求2)构建页面
  9. ASP.NET将ViewState数据添加到页面(此时没有)(请求2)
  10. ASP.NET将Post数据添加到页面(请求2)
  11. ASP.NET运行到达页面生命周期的“加载”步骤,并使用您的默认值添加您的特殊控件(请求2)
  12. 您现在处于您所看到的问题状态。
  13. 所以问题在于,当将数据添加到页面时,动态加载的控件不存在。当你添加它时,你将默认值放入.ASP.NET不再有机会用适当的数据填充它。