2010-03-31 56 views
3

我有一個包含名爲PhoneInfo.ascx的控件的頁面。 PhoneInfo是使用LoadControl()動態創建的,然後initControl()函數被調用傳入初始化對象以在PhoneInfo中設置一些初始文本框值。.net在頁面生命週期中的ViewState

然後,用戶更改這些值,並在連接到「submit_click」事件的頁面上點擊提交按鈕。此事件調用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(); 
} 

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; 
    } 
} 

回答

1

與思考者一樣,我認爲存在這個問題是因爲我設置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; 
} 
0

ViewState是初始化和加載事件之間的管理。當您關心保留回發值時,您應該利用Page_Init處理程序中調用的代碼或函數而不是Page_Load。

有關ASP.NET頁面生命週期的更多信息,請參閱此鏈接。

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

+0

我理解生命週期的這一部分,並同意最好的地方是page_init。但是,爲什麼用戶輸入的值通過我的GetPhone函數,如果它們通過viewstate回發保存?那些還不應該回歸爲空嗎? – caltrop 2010-03-31 17:58:14

0

做的正是你在做什麼,你必須有在頁面生命週期的Init部分加載的控制。

但是,要更輕鬆地做到這一點,爲什麼不將它添加到<asp:ContentPlaceHolder>?我認爲這會讓這更容易。

+0

感謝您的佔位符建議,但由於我遺漏了代碼的複雜性,佔位符在這裏並不理想。 =) 我明白足夠的生命週期,知道把它放在Init中會導致ViewState保存並被正確加載......我想我很困惑,爲什麼用戶輸入的文本會工作考慮它通過視圖狀態。 – caltrop 2010-03-31 17:57:01

0

基於評論回覆,我在這裏添加了另一個答案,它解釋了頁面生命週期的一部分,以及它對post和viewstate數據的意義。下面是一個關於事件的版本頁面生命週期的開始更加英語(到DEV)和少:

  1. 用戶請求一個頁面(請求1)
  2. 構建ASP.NET使用默認頁在字段中的值(請求1)
  3. 在你的Page_Load,你與你的默認值添加這個特殊的控制(請求1)
  4. 你這個頁面發送給用戶(請求1)
  5. 用戶數據發佈到頁面(請求2)
  6. ASP.NET構建t他從你的ASPX文件頁面(請求2)
  7. ASP。NET將ViewState數據添加到頁面(此時沒有)(請求2)
  8. ASP.NET將Post數據添加到頁面(請求2)
  9. ASP.NET運行到達Load步驟頁面生命週期並將您的特殊控制與您的默認值相加(請求2)
  10. 您現在處於有問題的狀態,您正在看到。

所以這裏的問題是,當發佈數據添加到頁面時,您的動態加載控件不存在。當您添加它時,您將默認值放入。ASP.NET不再有機會使用正確的數據填充它。

+0

對於它的價值,'Init'事件在本摘要的第6步和第7步之間。更具體地說,步驟6是「PreInit」事件。 – Jaxidian 2010-03-31 18:10:05

+0

這很有道理。我希望我的實際代碼可以讓我簡單地將創建代碼移動到Page_init,但它不會。我必須找出一些方法來解決問題。謝謝您的幫助! – caltrop 2010-03-31 19:42:16