页面生命周期中的.net ViewState

发布于 2024-08-27 06:36:09 字数 1862 浏览 10 评论 0原文

我有一个页面,其中包含一个名为 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

萌能量女王 2024-09-03 06:36:09

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

被你宠の有点坏 2024-09-03 06:36:09

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

显然,在初始化之后,.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;
}

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.

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;
}
傲性难收 2024-09-03 06:36:09

为了准确地完成您正在做的事情,您必须在页面生命周期的 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.

删除→记忆 2024-09-03 06:36:09

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

  1. 用户请求页面(请求 1)
  2. 字段中的默认值构建页面(请求 1)
  3. ASP.NET使用 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 运行到页面生命周期的 Load 步骤并使用默认值添加特殊控件(请求 2)
  10. 您现在处于所看到的有问题的状态。

所以这里的问题是当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:

  1. User requests a page (request 1)
  2. ASP.NET builds the page with default values in fields (request 1)
  3. On your Page_Load, you add this special control with your default values (request 1)
  4. You send this page to the user (request 1)
  5. The user posts data to the page (request 2)
  6. ASP.NET builds the page from your ASPX file (request 2)
  7. ASP.NET adds the ViewState data to the page (at this time, there is none) (request 2)
  8. ASP.NET adds the Post data to the page (request 2)
  9. ASP.NET runs reaches the Load step of the Page Lifecycle and adds your special control with your default values (request 2)
  10. You are now in the problematic state that you are seeing.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文