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

Posted

技术标签:

【中文标题】Winforms treeview,递归检查子节点问题【英文标题】:Winforms treeview, recursively check child nodes problem 【发布时间】:2011-03-11 14:31:49 【问题描述】:

以下代码直接取自微软http://msdn.microsoft.com/en-us/library/system.windows.forms.treeview.aftercheck%28VS.80%29.aspx。

  // Updates all child tree nodes recursively.
  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);
    
   
  

  // NOTE   This code can be added to the BeforeCheck event handler instead of the AfterCheck event.
  // After a tree node's Checked property is changed, all its child nodes are updated to the same value.
  private void node_AfterCheck(object sender, TreeViewEventArgs e)
  
   // The code only executes if the user caused the checked state to change.
   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);
    
   
  

你把它放在一个包含树视图的表单中,然后在树视图 AfterCheck 事件上调用 node_AfterCheck(惊喜,惊喜)。然后它递归地检查或取消选中树视图上的子节点。

但是,如果您真的尝试过,并且足够快地在同一个树视图复选框上单击几次,子节点最终会与父节点不同步。您可能需要几个级别的子级,总共可能有 100 个子级,以便 UI 更新足够慢以注意到这种情况。

我已经尝试了几件事(例如在 node_AfterCheck 开始时禁用树视图控件并在结束时重新启用),但仍然会出现不同步问题。

有什么想法吗?

【问题讨论】:

我已将我的解决方法发布到此主题的子主题中:***.com/questions/14699102/… 【参考方案1】:

.NET TreeView 类对本地 Windows 控件的鼠标处理进行了大量自定义,以便合成 Before/After 事件。不幸的是,他们并没有完全正确。当您开始快速单击时,您将生成双击消息。本机控件通过切换项目的选中状态来响应双击,不告诉 .NET 包装器。您不会收到 Before/AfterCheck 事件。

这是一个错误,但他们不会修复它。解决方法并不难,您需要阻止本机控件看到双击事件。向您的项目添加一个新类并粘贴如下所示的代码。编译。从工具箱顶部删除新控件,替换现有控件。

using System;
using System.Windows.Forms;

class MyTreeView : TreeView 
    protected override void WndProc(ref Message m) 
        // Filter WM_LBUTTONDBLCLK
        if (m.Msg != 0x203) base.WndProc(ref m);
    

【讨论】:

他们为什么不修复它? @Kamil 因为winforms 会死。他们迟早都会切换到WPF 我同意,但我对微软的发展方向不满意。奇怪的 Windows 8,奇怪的 Windows Phone,奇怪的 VS2012。东西更漂亮,但他们忘记了使用人体工程学。 一个不难的解决方法,除非复选框是 Internet Explorer 中的复选框。 2017 在这里签到,感谢解决方法,winforms 还没有死。【参考方案2】:

使用上面的解决方案,我认为需要绘制更详细的步骤,如何将其应用于那些想要将其应用于已经创建的 TreeView 的人。例如,对于我这个初学者来说,这会造成困难,但这里是解决方案:

    在您的项目中创建一个类“NoClickTree.cs”。

    在新类中包含此代码:

    public class NoClickTree : TreeView
    
        protected override void WndProc(ref Message m)
        
            // Suppress WM_LBUTTONDBLCLK
            if (m.Msg == 0x203)  m.Result = IntPtr.Zero; 
            else base.WndProc(ref m);
        
    
    

    转到Form1.Designer.cs"yourWindowWithTreeView".Designer.cs

    在文件末尾找到原始初始化,例如private System.Windows.Forms.TreeView treeView;

    将它们替换为private NoClickTree treeView;

    在函数private void InitializeComponent() 中找到原始初始化,类似于this.treeView = new System.Windows.Forms.TreeView();

    将它们替换为this.treeView = new NoClickTree();

    完成!

这些步骤帮助我解决了这个问题。

【讨论】:

以上是关于Winforms treeview,递归检查子节点问题的主要内容,如果未能解决你的问题,请参考以下文章

MFC Treeview:如何检查 Treeview 是不是已经包含特定的子节点?

VB.NET - 检查子节点是不是在 TreeView 中选中

如何在 WinForms 中禁用 TreeView 的节点重命名?

wpf treeview 数据绑定 递归绑定节点

WinForms TreeView - 如何手动“突出显示”节点(就像点击它一样)

怎么让所有子节点被选中,父节点自动选中 TreeView