页面生命周期中的.net ViewState

我有一个页面包含一个名为PhoneInfo.ascx的控件。 PhoneInfo是使用LoadControl()动态创建的,然后调用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代码隐藏

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

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

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

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

本文讨论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; } 

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

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

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

要完成您正在执行的操作,您必须在页面生命周期的Init部分中加载控件。

但是,为了更容易实现,为什么不将它添加到 ? 我认为这将使这更容易。

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

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

所以问题在于,当将数据添加到页面时,动态加载的控件不存在。 添加它时,将默认值放入.ASP.NET不再有机会使用正确的数据填充它。