从父节点中删除子节点

时间:2015-09-02 07:07:16

标签: c# .net winforms treeview

您好我目前有一个TreeView具有以下结构:

          • RootN
          • ChildN

    TreeView结构基本上可以有 NRootNodes - NChildren ,NRootNodes可以有 NRoots和NChildren ,所以基本上就像Windows资源管理器窗口一样。

我当前的问题是我必须得到所有的父母或根,在这种情况下 Roots / RootN 然后我必须删除所有他们的子节点,在本例中为 Child / ChildN 。最后,我必须只有父节点,然后克隆它们,以便我可以将它们移动到TreeView中的不同位置。

RootNodes有一个唯一的标签 - 文件夹,而ChildNodes有另一个唯一的标签 - 计算,正如我之前所说,我必须摆脱所选的所有计算节点,因此只有所选节点的结构将保留。

基本上我最终必须有这样的东西:

我有一个递归方法"扫描" SelectedNode并获取所有父母:

public  List<TreeNode> CollectParentNodes(TreeNodeCollection parentCollection, List<TreeNode> collectedNodes)
    {

        foreach (TreeNode node in parentCollection)
        {
            if (!collectedNodes.Contains(node.Parent))
            {
                collectedNodes.Add(node.Parent);
                parentNodeAdded = true;
            }

            if (node.Level != 0 && node.Tag.ToString() != Enumerations.NodeType.Calculation.ToString())
                collectedNodes.Add(node);

            if (node.Nodes.Count > 0)
                CollectParentNodes(node.Nodes, collectedNodes);
        }
        parentNodeAdded = false;
        return collectedNodes;
    }

最后我有一个列表可以容纳所有家长,但我面临的问题是家长还包含他们的后代,在这种情况下是计算

我搜索了Google和StackOverFlow,但我找不到任何帮助,如果已经回答,我会事先道歉。

谢谢。

3 个答案:

答案 0 :(得分:2)

您可以为TreeView创建一个返回List

的扩展方法GetAllNodes

请记住在代码顶部使用using System.Linq;

public static class Extensions
{
    public static List<TreeNode> GetAllNodes(this TreeView tree)
    {
        var firstLevelNodes = tree.Nodes.Cast<TreeNode>();
        return firstLevelNodes.SelectMany(x => GetNodes(x)).Concat(firstLevelNodes).ToList();
    }

    private static IEnumerable<TreeNode> GetNodes(TreeNode node)
    {
        var nodes = node.Nodes.Cast<TreeNode>();
        return nodes.SelectMany(x => GetNodes(x)).Concat(nodes);
    }
}

用法将是:

var result = this.treeView1.GetAllNodes().Where(x => x.Tag == "FOLDER").ToList();

请务必在代码顶部添加扩展程序类的命名空间,无论您希望在何处使用它。

作为示例,您可以将“文件夹”标签的“所有节点”设置为红色前景:

var result = this.treeView1.GetAllNodes().Where(x => (x.Tag as string) == "FOLDER").ToList();
result.ForEach(x => x.ForeColor = Color.Red);

这是一个截图

enter image description here

答案 1 :(得分:1)

这将创建一个新树,其中所选节点为root,哪些子节点仅包含标记为“Folder”的节点。
您需要创建一个复制构造函数(或扩展方法)来深度复制节点,以防止对节点对象的操作影响原始树源:

public TreeNode CollectFolderChildNodes(TreeNode selectedNode)
{
   if (selectedNode.Tag == "Calculation")
      return null;

   // Get all the children that are tagged as folder
   var childRootNodes = selectedNode.Children.Where((childNode) => childNode.Tag == "Folder";

   // Clone root node using a copy constructor
   var newRoot = new TreeNode(selectedNode);    
   newRoot.Children.Clear();

   foreach (var childNode in childRootNodes)
   { 
      // Iterate over all children and add them to the new tree
      if (childNode.Children.Any())
      {       
         // Repeat steps for the children of the current child. 
         // Recursion stops when the leaf is reached                    
         newRoot.Children.Add(CollectFolderChildNodes(childNode));             
      }     
      else
      {
        // The current child item is leaf (no children)
        newRoot.Children.Add(new TreeNode(childNode)); 
      }     
   }

   return newRoot;
}

我认为应该这样做,但我没有测试过。但也许至少它背后的想法是明确的。

但正如我之前提到的,也许最好遍历树(使用相同的ItemsSource)并将属性(例如 IsHidingCalculations )设置为true,这样只有文件夹将出现。您需要实施ItemsStyle,并在 IsHidingCalculations 评估为true时使用触发器将项Visibility设置为Collapsed

答案 2 :(得分:0)

要克隆没有子节点的节点,您可以创建如下的扩展方法:

public static TreeNode CloneWithoutChildren(this TreeNode node)
{
    return new TreeNode(node.Text, node.ImageIndex, node.SelectedImageIndex)
    {
         Name = node.Name,
         ToolTipText = node.ToolTipText,
         Tag = node.Tag,
         Checked = node.Checked
    }
}

然后:

collectedNodes.Add(node.CloneWithoutChildren());