Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 页面生命周期中的.net ViewState_C#_.net_Viewstate_Lifecycle_Pageload - Fatal编程技术网

C# 页面生命周期中的.net ViewState

C# 页面生命周期中的.net ViewState,c#,.net,viewstate,lifecycle,pageload,C#,.net,Viewstate,Lifecycle,Pageload,我有一个页面包含一个名为PhoneInfo.ascx的控件。PhoneInfo是使用LoadControl()动态创建的,然后调用initControl()函数传递初始化对象以在PhoneInfo中设置一些初始文本框值 然后用户更改这些值并点击页面上的提交按钮,该按钮连接到“提交点击”事件。此事件调用PhoneInfo中的GetPhone()函数。返回的值包含所有新用户输入的值,但phoneId值(存储在ViewState中且未由用户编辑)始终返回为空 我相信viewstate负责在回发过程中跟

我有一个页面包含一个名为PhoneInfo.ascx的控件。PhoneInfo是使用LoadControl()动态创建的,然后调用initControl()函数传递初始化对象以在PhoneInfo中设置一些初始文本框值

然后用户更改这些值并点击页面上的提交按钮,该按钮连接到“提交点击”事件。此事件调用PhoneInfo中的GetPhone()函数。返回的值包含所有新用户输入的值,但phoneId值(存储在ViewState中且未由用户编辑)始终返回为空

我相信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();
}
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数据的意义。以下是页面生命周期开始时的“更多英语版本(针对开发人员)”和“更少关于事件版本”:

  • 用户请求页面(请求1)
  • ASP.NET使用字段中的默认值生成页面(请求1)
  • 在页面加载中,使用默认值添加此特殊控件(请求1)
  • 您将此页面发送给用户(请求1)
  • 用户将数据发布到页面(请求2)
  • ASP.NET从您的ASPX文件生成页面(请求2)
  • ASP.NET将ViewState数据添加到页面(此时没有)(请求2)
  • ASP.NET将Post数据添加到页面(请求2)
  • ASP.NET运行达到页面生命周期的加载步骤,并使用默认值添加特殊控件(请求2)
  • 你现在处于你所看到的有问题的状态

  • 因此,这里的问题是,将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,但事实并非如此。我得想办法把东西搬来搬去。谢谢你的帮助!