`menu_ul.FindControl(id)` 返回 `null`,無法動態控制 `
public static Control FindControlRecursive(Control root, string id) {
if (root.ID == id) return root;
foreach (Control c in root.Controls) {
Control found = FindControlRecursive(c, id);
if (found != null) return found;
}
return null;
}
// 調用
HtmlGenericControl li = (HtmlGenericControl)FindControlRecursive(this.Page, menuId);
if (li != null) li.Visible = true;
string menuId = dt.Rows[i]["menu_id"].ToString(); // 確保值為 "menu_1" 等
HtmlGenericControl li = (HtmlGenericControl)FindControlRecursive(menu_ul, menuId);
// 或直接 menu_ul.FindControl(menuId) 若在同一命名容器
" runat="server"
visible='<%# Convert.ToBoolean(Eval("has_permission")) %>'>
<%# Eval("menu_name") %>
DataTable dt = GetUserMenuPermissions(userId); // 含 menu_id, menu_name, has_permission
rptMenu.DataSource = dt;
rptMenu.DataBind(); // 自動根據 has_permission 渲染 visible
| 概念 | 說明 |
|---|---|
| 命名容器 | 實現 `INamingContainer` 的控件,隔離 `FindControl` 作用域,確保 ID 在容器內唯一 |
| `FindControl` 作用域 | **僅當前命名容器**,不跨容器 |
| HTML 控件變伺服器控件 | 添加 `runat="server"`,生成 `HtmlGenericControl` 等對應類實例 |
| 動態查找最佳實踐 | 遞歸查找輔助方法 / 數據綁定驅動 UI (Repeater/ListView) / ClientIDMode=Static 便於 JS 操作 |
`FindControl` 返回 `null` 多因 **跨命名容器**、**前端缺 `runat="server"`**、**ID 不匹配**。**「遞歸查找輔助方法」可快速修復舊代碼**,「Repeater 數據綁定 `Visible` 屬性」是新開發的規範模式。理解命名容器機制,是 ASP.NET WebForms 動態控件操作的核心功力。