ASP.NET 動態建立控件 (Dynamic Controls) 必須在 **每次 PostBack 時重建**,且在 **ViewState 載入前** 完成 (通常在 OnLoad 或 OnInit),否則事件不觸發、值不保留。本文示範標準模式與常見坑點。
public partial class DynamicControlsDemo : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
CreateControls(); // 每次 PostBack 都要重建
}
protected void btnCreate_Click(object sender, EventArgs e)
{
ViewState["ControlsCreated"] = true;
CreateControls();
}
void CreateControls()
{
if (ViewState["ControlsCreated"] == null) return; // 首次不建立
for (int x = 0; x < 10; x++)
{
var row = new TableRow();
for (int y = 0; y < 10; y++)
{
var cell = new TableCell();
var btn = new Button
{
Text = $"x={x}, y={y}",
ID = $"btn_{x}_{y}" // 必須給 ID,否則 ViewState 無法對應
};
btn.Click += Btn_Click;
cell.Controls.Add(btn);
row.Cells.Add(cell);
}
HolderTable.Rows.Add(row);
}
}
void Btn_Click(object sender, EventArgs e)
{
var btn = (Button)sender;
btn.BackColor = System.Drawing.Color.Red;
Response.Write($"你點擊了:{btn.Text}");
}
protected void btnDisplay_Click(object sender, EventArgs e)
{
foreach (TableRow row in HolderTable.Rows)
foreach (TableCell cell in row.Cells)
if (cell.Controls[0] is Button btn)
Response.Write(btn.Text + " ");
}
}
| 規則 | 說明 |
|---|---|
| **ID 必須固定** | 動態控件跨 PostBack 需相同 ID 才能載入 ViewState/事件 |
| **每次 PostBack 重建** | 在 OnLoad/OnInit 中無條件重建 (或依旗標) |
| **事件綁定在重建時** | btn.Click += ... 必須在 CreateControls 內 |
| **容器控件需 runat=server** | Table, PlaceHolder, Panel 等皆可作為容器 |
!IsPostBack 建立 → PostBack 後控件消失、事件不觸發。btnCreate_Click 後未重建 → 新控件無事件、無 ViewState。理解動態控件生命週期,是 Web Forms 進階開發的必修課。