[UserControl] 網頁生命週期與取不到 UserControl 資料的問題

如果你寫 ASP.NET 的程式夠久, 你就會知道網頁會發生的大部份奇怪的問題都發生在沒有弄清楚網頁生命週期這個原因。而如果你在 ASP.NET 上面的除錯經驗老道, 你就會很直覺的把很多奇怪的問題懷疑到網頁生命週期這個方向。幸好我們有很簡單的方法可以知道這方面的問題, 如果你不知道, 或是不熟悉, 你最好看看我以下的介紹...

 

如果你寫 ASP.NET 的程式夠久, 你就會知道網頁會發生的大部份奇怪的問題都發生在沒有弄清楚網頁生命週期這個原因。而如果你在 ASP.NET 上面的除錯經驗老道, 你就會很直覺的把很多奇怪的問題懷疑到網頁生命週期這個方向。幸好我們有很簡單的方法可以知道這方面的問題, 如果你不知道, 或是不熟悉, 你最好看看我以下的介紹。

要了解網頁生命週期, 最簡單的方法就是在 .aspx 最上面那一行加上兩個屬性:

<%@ Page ...Trace="true" Debug="true" %>

當你這麼做之後, 網頁開啟時, 你會在網頁內容的下方看到很長的除錯訊息, 其中包含很多很有用的資訊, 例如表頭、Cookies、所有控制項的 ID 等等。不過在這裡我們要注意的是它的「追蹤資訊」。在這裡你可以注意到很多網頁事件的執行時間和發生的順序, 例如一開始的 Begin PreInit 事件, 最後的 End Render 等等。

不過, 很可惜的, 你雖然看得到網頁本身 (.aspx) 的生命週期, 你卻看不到 UserControl (.ascx) 的生命週期。如果你要知道不同事件的發生順序, 你必須在程式中加上如下的程式:

using System.Diagnostics;
...
void Page_Init(object sender, EventArgs e)
{
    Trace.Write("uc Page_Init starts...");
    ...

使用 Trace.Write 或 Trace.Warn (兩者功用相同, 只是後者會輸出紅色粗體字) 可以在上述的「追蹤資訊」段落中輸出你想要看到的資訊。如果你沒有設定 <%@ Page ...Trace="true" Debug="true" %> 的話, 則這段指令不會發生任何作用。

利用這個功能, 你可以把 Trace.Write 塞進各個事件裡面 (例如 .aspx 的 Page_Load, .ascx 的 Page_Lod, 甚至 .ascx 的某個控制項的 DataBound 事件等等), 再利用追蹤頁面觀察各個事件的前後順序。只要你懂得運用這個方法, 你就能完全掌握網頁中任何控制項的任何事件在整個網頁生命週期的發生順序, 再也不用去查什麼網頁生命週期表了。

以我最近看到的一個問題為例, 使用者發現在網頁的 Page_Load 事件中無法設定某個 UserControl 的控制項內容。透過追蹤頁面的資訊, 我發現原來使用者將 UserControl 的資料繫結動作留在該控制項的 Page_Load 事件中做, 而 .ascx 的 Page_Load 事件實際上發生在 .aspx 的 Page_Load 事件之後。換句話說, 使用者企圖在 .aspx 的 Page_Load 事件中存取 .ascx 的控制項, 但那時候資料繫結根本還沒發生, 當然就存取不到任何東西了。

在這種情況之下, 有一個很簡單的解決方法, 那就是把 .ascx 的資料繫結動作從 Page_Load 移到 Page_Init 事件裡面去做。從追蹤頁面中我們可以發現 .ascx 的 Page_Init 事件確實發生在 .aspx 的 Page_Load 事件之前, 所以就可以放心的採用這個做法, 同時也解決了原來的問題。


Dev 2Share @ 點部落