TreeView 配合 CheckBox 是權限分配、分類篩選、組織架構等場景的標準 UI。本文提供「父選子全選、子全取消父取消、子部分選中父三態」完整遞歸實現,代碼可直接落地生產。
private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) {
// 僅響應用戶交互,避免程序賦值觸發死循環
if (e.Action != TreeViewAction.ByMouse) return;
if (e.Node.Checked) {
// 父節點被勾選 → 所有子孫勾選
SetChildNodesChecked(e.Node, true);
} else {
// 父節點被取消 → 所有子孫取消
SetChildNodesChecked(e.Node, false);
// 向上檢查父節點狀態
UpdateParentNodesChecked(e.Node);
}
}
/// 遞歸設置子孫節點 Checked 狀態
private void SetChildNodesChecked(TreeNode node, bool check) {
foreach (TreeNode child in node.Nodes) {
child.Checked = check;
if (child.Nodes.Count > 0) SetChildNodesChecked(child, check);
}
}
/// 遞歸更新祖先節點狀態 (勾選/取消/三態)
private void UpdateParentNodesChecked(TreeNode node) {
var parent = node.Parent;
if (parent == null) return;
bool allChecked = true, allUnchecked = true;
foreach (TreeNode sibling in parent.Nodes) {
if (sibling.Checked) allUnchecked = false;
else allChecked = false;
if (!allChecked && !allUnchecked) break; // 提前退出
}
if (allChecked) parent.Checked = true;
else if (allUnchecked) parent.Checked = false;
else parent.CheckState = CheckState.Indeterminate; // 三態:方塊中帶短橫線
// 繼續向上遞歸
UpdateParentNodesChecked(parent);
}
| 技術點 | 說明 |
|---|---|
| TreeViewAction.ByMouse | 過濾程序賦值觸發的 AfterCheck,防止遞歸死循環 |
| CheckState.Indeterminate | 父節點「部分選中」視覺狀態,需 TreeView.CheckBoxes=true |
| 遞歸終止條件 | Nodes.Count == 0 (葉節點) 或 父節點為 null (根節點) |
| 性能優化 | 兄弟節點遍歷中提前判斷混合狀態 break,減少無用迭代 |
public ListGetCheckedNodes(TreeNodeCollection nodes) { var result = new List (); foreach (TreeNode node in nodes) { if (node.Checked) result.Add(node); // 三態節點視為「部分選中」,業務邏輯自定:是否包含其勾選的子孫 if (node.Nodes.Count > 0) result.AddRange(GetCheckedNodes(node.Nodes)); } return result; }
TreeView 聯動選中核心是 「向下廣播、向上匯總」 遞歸模型。善用 TreeViewAction.ByMouse 區分用戶操作與程序賦值,正確處理 CheckState.Indeterminate 三態,即可構建符合直覺、體驗流暢的樹形勾選交互。