ASP.NET WebForms 頁面生命週期事件繁多、順序嚴格。本文通過父頁、用戶控件、子控件三層代碼實例,演示 OnInit、OnLoad、ViewState、事件冒泡的協同運作。
PreInit → Init → InitCompletePreLoad → Load → LoadCompletePreRender → PreRenderCompleteSaveStateComplete → Render → Unload關鍵原則:父控件事件先於子控件;Init 階段建立控件樹、綁定事件;Load 階段處理回傳資料、ViewState 已恢復。
public class UserParentPage : System.Web.UI.Page {
protected override void OnInit(EventArgs e) {
// 1. SQL 注入防護:檢查 QueryString/Form 可疑字符
// 2. 全域權限檢查、文化設置、主題套用
base.OnInit(e);
}
protected override void OnLoad(EventArgs e) {
// 3. 頁面級資料載入、快取策略
base.OnLoad(e);
}
}
public partial class UserEventControl : System.Web.UI.UserControl {
public delegate void ChangedHandler();
public event ChangedHandler Changed; // 對外暴露事件
private void Page_Load(object sender, EventArgs e) {
if (!Page.IsPostBack) SetContent(); // 首次載入綁定資料
}
private void SetContent() {
// 動態生成 Table + LinkButton,每個按鈕綁定 __doPostBack
// 關鍵:ClientID 替換 "_" 為 "$" 以符合事件目標格式
}
protected override void OnInit(EventArgs e) {
InitializeComponent(); // 綁定 Click 事件
base.OnInit(e);
}
private void lbtnShow_Click(object sender, EventArgs e) {
CurrentID = Request.Form["__EVENTARGUMENT"]; // 獲取回傳參數
SetContent(); // 重新綁定(因樣式可能改變)
Changed?.Invoke(); // 冒泡事件通知父頁
}
public string CurrentID {
get => (string)ViewState["CurrentID"]; // ViewState 跨回傳保持狀態
set => ViewState["CurrentID"] = value;
}
}
public partial class ConsumerPage : UserParentPage {
protected void UserEventControl1_Changed(object sender, EventArgs e) {
// 子控件觸發 Changed 事件後執行
// 可讀取 UserEventControl1.CurrentID 執行業務邏輯
}
}
// .aspx 中註冊
<%@ Register Src="~/Controls/UserEventControl.ascx" TagPrefix="uc" TagName="UserEventControl" %>
<uc:UserEventControl ID="UserEventControl1" runat="server" OnChanged="UserEventControl1_Changed" />
| 機制 | 關鍵點 | 常見錯誤 |
|---|---|---|
| ViewState | 僅序列化標記 EnableViewState=true 的控件屬性;自定義屬性必須手動存取 ViewState[key] | 在 Init 前存取 ViewState 為 null;大量資料導致頁面膨脹 |
| 事件冒泡 | 子控件 RaiseBubbleEvent → 父控件 OnBubbleEvent → 頁面 RaisePostBackEvent | 動態建立控件未在 Init 階段重建,事件不觸發 |
| __doPostBack | 生成 __EVENTTARGET (控件 UniqueID) + __EVENTARGUMENT (自定義參數) | ClientID 與 UniqueID 混淆,導致目標控件找不到 |
Page.Trace 或 Trace.axd 監控生命週期耗時與 ViewState 大小。