ASP.NET 動態建立控件(如 WebPartZone)必須在 OnInit 階段完成,但按鈕點擊事件發生在 OnLoad 之後,且 ViewState 在 OnLoad 才可用。本文提出利用 HiddenField + Request.Form 繞過生命週期限制的實作方案。
OnInit 建立,否則拋出異常Click 事件在 RaisePostBackEvent(OnLoad 後)觸發ViewState 在 LoadViewState(OnLoad 前)載入,OnInit 時不可用OnInit 讀不到 ViewState<asp:HiddenField ID="hfCount" runat="server" Value="0" />
<asp:Button ID="btnAdd" runat="server" Text="Add" OnClick="btnAdd_Click" />
<asp:PlaceHolder ID="PlaceHolder1" runat="server" />
public partial class _Default : Page
{
private int _count = 0;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// 1. 從 Request.Form 直接讀取 HiddenField 值(繞過 ViewState)
if (!String.IsNullOrEmpty(Request["hfCount"]))
_count = Convert.ToInt32(Request["hfCount"]);
// 2. 判斷是否點擊 Add(檢查按鈕 name 是否在 Form 中)
if (Request["btnAdd"] == "Add")
_count++;
// 3. 動態建立控件
for (int i = 0; i < _count; i++)
{
TextBox tb = new TextBox { ID = "TXT" + i };
PlaceHolder1.Controls.Add(tb);
}
}
protected void Page_Load(object sender, EventArgs e)
{
// 同步更新 HiddenField,供下次 PostBack 使用
hfCount.Value = _count.ToString();
}
protected void btnAdd_Click(object sender, EventArgs e)
{
// 故意留空:真正邏輯在 OnInit
}
}
HiddenField 渲染為 <input type="hidden" name="hfCount" value="...">,PostBack 時包含在 Request.Form 中Request.Form 在 OnInit 即可存取,不依賴 ViewStatename=value 送入 Request.Form,可作為觸發條件判斷Page_Load 更新 HiddenField.Value,確保下一輪 PostBack 狀態正確| 方案 | 優點 | 缺點 |
|---|---|---|
| HiddenField + Request.Form | 不依賴 ViewState,相容所有控件 | 程式碼分散在 OnInit/Load,語意不清 |
| 動態控件重建於 Page_Load + ViewState 保存狀態 | 符合標準模式 | WebPartZone 等特定控件不支援 |
| 使用 UpdatePanel 區部更新 | 避免完整 PostBack | 仍需在 OnInit 建立靜態控件樹 |
建議:現代專案優先考慮客戶端渲染(jQuery/Vue/React)動態增減 DOM,僅在伺服器端需保留狀態時使用 HiddenField 傳遞最小資料集。