TreeView检查/取消检查所有子项

如何检查/取消选中TreeView中的所有子项? 当其中一个项目变为选中状态和子项目选中/未检查错误时,可能发生错误。

链接到VS 2010 Project + Exe

YOUTUBE上的video

private void Form1_Load(object sender, EventArgs e) { treeView1.CheckBoxes = true; treeView1.BeginUpdate(); treeView1.Nodes.Add("1111"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes[1].Nodes.Add("3333"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.EndUpdate(); treeView1.ExpandAll(); } private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { treeView1.BeginUpdate(); foreach (TreeNode Node in e.Node.Nodes) { Node.Checked = e.Node.Checked; } treeView1.EndUpdate(); } 

使用Form_Load中的代码保留它的代码,并在代码中添加这两种方法

 private void Form1_Load(object sender, EventArgs e) { treeView1.CheckBoxes = true; treeView1.BeginUpdate(); treeView1.Nodes.Add("1111"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes.Add("2222"); treeView1.Nodes[0].Nodes[1].Nodes.Add("3333"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.Nodes[0].Nodes[1].Nodes[0].Nodes.Add("4444"); treeView1.EndUpdate(); treeView1.ExpandAll(); } private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { foreach (TreeNode childNode in e.Node.Nodes) { childNode.Checked = e.Node.Checked; } } 

我发现的解决方案如下:

  • 为了执行选择,我使用了Linq:

    if (e.Node.Nodes.Count > 0) e.Node.Nodes.Cast().Where(tnc => tnc.Checked != e.Node.Checked).ForEach(tn => tn.Checked = e.Node.Checked);

  • 然后为了处理事件选择,我扩展了TreeView类: public class MyTV : TreeView { protected bool TopOfCascade; TreeNode startNode; public Action FinishedCheckEventsDelegate; public Action InitiateCascadeCheckEventsDelegate; public MyTV() : base() { TopOfCascade = false; startNode = null; } protected override void OnBeforeCheck(TreeViewCancelEventArgs e) { base.OnBeforeCheck(e); if (!TopOfCascade && !e.Cancel) { TopOfCascade = true; startNode = e.Node; if (InitiateCascadeCheckEventsDelegate != null) InitiateCascadeCheckEventsDelegate(); } } protected override void OnAfterCheck(TreeViewEventArgs e) { base.OnAfterCheck(e); if (startNode == e.Node && e.Action != TreeViewAction.Unknown) { if (FinishedCheckEventsDelegate != null) FinishedCheckEventsDelegate(); TopOfCascade = false; startNode = null; } } public class MyTV : TreeView { protected bool TopOfCascade; TreeNode startNode; public Action FinishedCheckEventsDelegate; public Action InitiateCascadeCheckEventsDelegate; public MyTV() : base() { TopOfCascade = false; startNode = null; } protected override void OnBeforeCheck(TreeViewCancelEventArgs e) { base.OnBeforeCheck(e); if (!TopOfCascade && !e.Cancel) { TopOfCascade = true; startNode = e.Node; if (InitiateCascadeCheckEventsDelegate != null) InitiateCascadeCheckEventsDelegate(); } } protected override void OnAfterCheck(TreeViewEventArgs e) { base.OnAfterCheck(e); if (startNode == e.Node && e.Action != TreeViewAction.Unknown) { if (FinishedCheckEventsDelegate != null) FinishedCheckEventsDelegate(); TopOfCascade = false; startNode = null; } } 在主机控件中,您可以挂钩前后级联事件并迭代所有已检查/未检查的树节点,从而避免大量交叉事件触发。 您可以通过某个容器控制级联。

我从以下Web实现中获取了ForEach到IEnumerable:

 public static void ForEach(this IEnumerable source, Action action) { if (source == null) throw new ArgumentNullException("source"); if (action == null) throw new ArgumentNullException("action"); foreach (T item in source) { action(item); } } 

祝好运!

这是一个答案(来自Hans Passant):

Winforms treeview,递归检查子节点问题

我把它写成答案,而不是评论,以便更容易找到。

  private void treeView1_AfterCheck(object sender, TreeViewEventArgs e) { if (e.Action != TreeViewAction.Unknown) { if (e.Node.Nodes.Count > 0) { /* Calls the CheckAllChildNodes method, passing in the current Checked value of the TreeNode whose checked state changed. */ this.CheckAllChildNodes(e.Node, e.Node.Checked); } } } private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked) { foreach (TreeNode node in treeNode.Nodes) { node.Checked = nodeChecked; if (node.Nodes.Count > 0) { // If the current node has child nodes, call the CheckAllChildsNodes method recursively. this.CheckAllChildNodes(node, nodeChecked); } } } 
  private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked) { foreach (TreeNode node in treeNode.Nodes) { node.Checked = nodeChecked; if (node.Nodes.Count > 0) { this.CheckAllChildNodes(node, nodeChecked); } } } private void treeView_AfterCheck(object sender, TreeViewEventArgs e) { if (e.Action != TreeViewAction.Unknown) { if (e.Node.Nodes.Count > 0) { if (!e.Node.Checked) { this.CheckAllChildNodes(e.Node, e.Node.Checked); } } } if (e.Node.Parent != null) { TreeNode n = e.Node; while (n.Parent != null) { if (n.Checked) { n.Parent.Checked = true; } n = n.Parent; } } }