【问题标题】:.net ViewState in page lifecycle页面生命周期中的 .net ViewState
【发布时间】:2010-04-01 22:17:37
【问题描述】:

我有一个页面,其中包含一个名为 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;
    }
}

【问题讨论】:

    标签: c# .net viewstate lifecycle pageload


    【解决方案1】:

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

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

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

    【讨论】:

    • 我了解生命周期的这一部分,并同意最好的地方是 page_init。但是,如果用户输入的值是通过视图状态的回发保存的,为什么它们会通过我的 GetPhone 函数呢?那些不应该也返回为 null 吗?
    【解决方案2】:

    我和回答者一样认为存在这个问题是因为我将 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;
    }
    

    【讨论】:

      【解决方案3】:

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

      但是,为了更容易做到这一点,为什么不将其添加到<asp:ContentPlaceHolder> 中呢?我认为这会使这变得容易得多。

      【讨论】:

      • 感谢占位符的建议,但由于我遗漏了代码的复杂性,占位符在这里并不理想。 =) 我对生命周期的了解足以知道将其放入 Init 将导致 ViewState 保存并正确加载...我想我很困惑为什么用户输入的文本确实可以工作,因为它会通过 viewstate 作为好吧。
      【解决方案4】:

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

      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 不再有机会使用正确的数据填充它。

      【讨论】:

      • 不管怎样,Init 事件位于本摘要的第 6 步和第 7 步之间。更具体地说,第 6 步是 PreInit 事件。
      • 这很有意义。我希望我的实际代码允许我简单地将创建代码移动到 Page_init,但事实并非如此。我得想办法把东西搬来搬去。感谢您的帮助!
      猜你喜欢
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 2011-05-30
      相关资源
      最近更新 更多