C# 页面生命周期中的.net ViewState
我有一个页面包含一个名为PhoneInfo.ascx的控件。PhoneInfo是使用LoadControl()动态创建的,然后调用initControl()函数传递初始化对象以在PhoneInfo中设置一些初始文本框值 然后用户更改这些值并点击页面上的提交按钮,该按钮连接到“提交点击”事件。此事件调用PhoneInfo中的GetPhone()函数。返回的值包含所有新用户输入的值,但phoneId值(存储在ViewState中且未由用户编辑)始终返回为空 我相信viewstate负责在回发过程中跟踪用户输入的数据,因此我无法理解用户值是如何返回的,但无法理解显式设置的viewstate[“PhoneId”]值!如果我在PhoneInfo的page_load事件中设置ViewState[“PhoneId”]值,它会在回发后正确检索该值,但这不是一个选项,因为我只能在页面准备提供该值时初始化该值 我肯定我只是把页面生命周期搞砸了,任何建议或问题都会很有帮助!我在下面包含了实际代码的简化版本 包含页面的代码隐藏C# 页面生命周期中的.net ViewState,c#,.net,viewstate,lifecycle,pageload,C#,.net,Viewstate,Lifecycle,Pageload,我有一个页面包含一个名为PhoneInfo.ascx的控件。PhoneInfo是使用LoadControl()动态创建的,然后调用initControl()函数传递初始化对象以在PhoneInfo中设置一些初始文本框值 然后用户更改这些值并点击页面上的提交按钮,该按钮连接到“提交点击”事件。此事件调用PhoneInfo中的GetPhone()函数。返回的值包含所有新用户输入的值,但phoneId值(存储在ViewState中且未由用户编辑)始终返回为空 我相信viewstate负责在回发过程中跟
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();
}
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;
}
}
PhoneInfo.ascx codebehind
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();
}
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在初始化和加载事件之间进行管理。在维护回发的值时,应该使用Page_Init处理程序中的代码或调用的函数,而不是Page_Load 有关ASP.NET页面生命周期的详细信息,请参阅此链接
要准确执行您正在执行的操作,必须在页面生命周期的
Init
部分加载控件
但是,为了更容易地执行,为什么不将其添加到
中呢?我认为这样做会更容易。根据评论回复,我在这里添加另一个答案,解释页面生命周期的一部分,以及它对post和viewstate数据的意义。以下是页面生命周期开始时的“更多英语版本(针对开发人员)”和“更少关于事件版本”:
因此,这里的问题是,将post数据添加到页面时,动态加载的控件不存在。添加它时,将默认值放入。ASP.NET不再有机会用适当的数据填充它。我和回答者一样,认为存在这个问题,因为我设置ViewState变量太晚,无法在SaveViewState期间保存。但是,我为SaveViewState事件添加了一个覆盖,果然早在保存ViewState之前就设置了ViewState变量。事实证明,这是很久以前的事了 显然在初始化之后,.net运行TrackViewState(),它实际上开始侦听您添加的任何viewState变量。因为我在TrackViewState()运行之前设置了这个viewState值,所以看起来一切正常,但在SaveViewState期间并没有实际添加这些值。在设置变量之前,我显式调用了TrackViewState(),一切都按预期进行 我的最终解决方案是通过初始化指定一个私有属性来保存ID值,然后在SaveViewState期间从属性值设置viewState变量。通过这种方式,我可以确保TrackViewState由.net运行,而不必显式调用它,从而打乱了流程。我在加载页面上重新加载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;
}
感谢占位符建议,但由于我遗漏的代码的复杂性,占位符在这里并不理想。=)我对生命周期非常了解,知道将其放入Init将导致ViewState保存并正确加载。。。考虑到用户输入的文本也会经过viewstate,我想我很困惑,为什么用户输入的文本会起作用。我理解生命周期的这一部分,并同意最好的位置是在page_init上。但是,如果用户输入的值是通过viewstate的回发保存的,那么为什么用户输入的值会进入我的GetPhone函数呢?这些不应该也返回为null吗?值得一提的是,
Init
事件位于本摘要的步骤6和步骤7之间。更具体地说,步骤6是PreInit
事件。这很有意义。我希望我的实际代码能够允许我简单地将创建代码移动到Page_init,但事实并非如此。我得想办法把东西搬来搬去。谢谢你的帮助!