需求:使用者點擊「新增」按鈕 PostBack 後,動態建立使用者控制項實例並加入頁面,且跨 PostBack 保持狀態。解決方案:PlaceHolder 容器 + BasePage 基類封裝動態載入邏輯 + Session 保存控制項資訊。
public class BasePage : System.Web.UI.Page
{
private const string SESSION_CONTAINERS_KEY = "Controls_In_Container";
private const string PATH_TO_CONTROL = "~/App_Controls/{0}";
protected void AddControl(string controlName, string placeHolderId)
{
// 1. 從 Session 取得已加入控制項清單
List<ControlInfo> controls = Session[SESSION_CONTAINERS_KEY] as List<ControlInfo>
?? new List<ControlInfo>();
// 2. 建立新控制項資訊
controls.Add(new ControlInfo { ControlName = controlName, PlaceHolderId = placeHolderId });
Session[SESSION_CONTAINERS_KEY] = controls;
// 3. 立即載入並加入對應 PlaceHolder
LoadControlToPlaceholder(controlName, placeHolderId);
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// 頁面初始化時,從 Session 還原所有動態控制項
RestoreDynamicControls();
}
private void RestoreDynamicControls()
{
var controls = Session[SESSION_CONTAINERS_KEY] as List<ControlInfo>;
if (controls != null)
{
foreach (var info in controls)
{
LoadControlToPlaceholder(info.ControlName, info.PlaceHolderId);
}
}
}
private void LoadControlToPlaceholder(string controlName, string placeHolderId)
{
Control ctrl = LoadControl(string.Format(PATH_TO_CONTROL, controlName));
PlaceHolder ph = FindControlRecursive(this, placeHolderId) as PlaceHolder;
if (ph != null) ph.Controls.Add(ctrl);
}
// 遞迴尋找控制項(支援 MasterPage、命名容器)
private Control FindControlRecursive(Control root, string id) { ... }
}
public class ControlInfo
{
public string ControlName { get; set; }
public string PlaceHolderId { get; set; }
}
BasePage。<asp:PlaceHolder ID="ph1" runat="server" />。AddControl("MyUserControl.ascx", "ph1")。此模式解決動態控制項生命週期與狀態保持難題,結構清晰、可重用,是 ASP.NET WebForm 開發常用進階技巧。