页面生命周期中的.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;
}
}
I have a page containing a control called PhoneInfo.ascx. PhoneInfo is dynamically created using LoadControl() and then the initControl() function is called passing in an initialization object to set some initial textbox values within PhoneInfo.
The user then changes these values and hits a submit button on the page which is wired up to the "submit_click" event. This event invokes the GetPhone() function within PhoneInfo. The returned value has all of the new user entered values except that the phoneId value (stored in ViewState and NOT edited by the user) always comes back as null.
I believe that the viewstate is responsible for keeping track of user entered data across a postback, so I can't understand how the user values are coming back but not the explicitly set ViewState["PhoneId"] value! If I set the ViewState["PhoneId"] value in PhoneInfo's page_load event, it retrieves it correctly after the postback, but this isn't an option because I can only initialize that value when the page is ready to provide it.
I'm sure I am just messing up the page lifecycle somehow, any suggestion or questions would really help! I have included a much simplified version of the actual code below.
Containing page's 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();
}
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;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
ViewState 在 Init 和 Load 事件之间进行管理。当您关心维护回发的值时,您应该使用 Page_Init 处理程序中的代码或调用的函数,而不是 Page_Load。
有关 ASP.NET 页面生命周期的更多信息,请参阅此链接。
http://msdn.microsoft.com/en-us/library/ms178472。 ASPX
ViewState is managed between the Init and Load events. You should utilize code in or functions called from the Page_Init handler instead of Page_Load when you are concerned with maintaining values from postbacks.
See this link for more information on the ASP.NET page life cycle.
http://msdn.microsoft.com/en-us/library/ms178472.aspx
我和回答者一样认为,这个问题的存在是因为我设置 ViewState 变量太晚,无法在 SaveViewState 期间保存。但是,我为 SaveViewState 事件添加了覆盖,并且果然我在保存 ViewState 之前很久就设置了 ViewState 变量。事实证明,时间太早了。
显然,在初始化之后,.net 运行 TrackViewState(),它实际上开始侦听您添加的任何 viewState 变量。由于我在 TrackViewState() 运行之前设置了此 viewState 值,因此一切看起来都很好,但在 SaveViewState 期间实际上并未添加这些值。我在设置变量之前明确调用了 TrackViewState(),一切都按预期工作。
我的最终解决方案是分配一个私有属性来通过初始化保存 ID 值,然后在 SaveViewState 期间从属性值设置 viewState 变量。这样我就可以确保 TrackViewState 已由 .net 运行,而不必显式调用它并扰乱事物的流程。我在 page_load 上重新加载 viewState 值,并使用它来设置属性的值,然后我可以在 GetPhone 函数中使用该值。
这篇文章讨论了enableViewState。
I thought, like the answerers, that this problem existed because I was setting the ViewState variable too late to be saved during SaveViewState. However, I added an override for the SaveViewState event, and sure enough I was setting my ViewState variable long before the ViewState was saved. Too long before, it turns out.
Apparently after initialization, .net runs TrackViewState() which actually starts listening for any viewState variables you add. Since I had set this viewState value BEFORE TrackViewState() had run, everything appeared fine but the values were not actually being added during SaveViewState. I explicitly called TrackViewState() right before setting the variable and everything worked as expected.
My final solution was to assign a private property to hold the ID value through initialization and then to set the viewState variable during SaveViewState from the property value. This way I can ensure that TrackViewState has been run by .net without having to explicitly call it and mess up the flow of things. I reload the viewState value on page_load and use it to set the value of the property which I can then use in my GetPhone function.
This article talks about enableViewState.
为了准确地完成您正在做的事情,您必须在页面生命周期的
Init
部分中加载控件。但是,为了更轻松地做到这一点,为什么不将其添加到
中?我认为这会让事情变得更容易。To do exactly what you're doing, you have to have the control loaded in the
Init
portion of the page lifecycle.However, to do it more easily, why don't you add it to an
<asp:ContentPlaceHolder>
? I think it will make this much easier.根据评论回复,我在这里添加另一个答案,解释页面生命周期的一部分以及它对帖子和视图状态数据的含义。下面是页面生命周期开始时的更多英语(对于开发人员)和更少关于事件的版本:
所以这里的问题是当post数据添加到页面时,你的动态加载的控件不存在。添加它时,您将默认值放入其中。ASP.NET 不再有机会使用正确的数据填充它。
Based on the comment responses, I'm adding another answer here that explains a part of the Page Lifecycle and what it means for post and viewstate data. Below is a more in-English (to a dev) and less about events version of the beginning of the page lifecycle:
So the problem here is that your dynamically-loaded control does not exist when post data is added to the page. When you add it, you put your default values in. ASP.NET no longer has a chance to populate it with the proper data.