从 Parent 个节点中删除 Child 个节点

Remove Child Nodes from Parent Node

你好,我目前有一个 TreeView 结构如下:

我目前的问题是我必须获得所有 Parents 或 Root,在本例中为 Roots / RootN 然后我必须删除他们所有的 Child 节点,在这种情况下 Child / ChildN 。最后,我只需要 Parent 个节点,然后克隆它们,这样我就可以将它们移动到 TreeView 中的不同位置。

RootNodes 有一个独特的标签 - Folder 和 ChildNodes 有另一个独特的标签 - Calculations,正如我所说早些时候,我必须摆脱选定节点中的所有计算,因此只保留该选定节点的结构。

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

我有一个递归方法 "scans" SelectedNode 并获取所有 Parents:

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;
    }

最后我有一个包含所有 Parent 的列表,但我面临的问题是 Parent 也包含它们的后代,在这种情况下 计算

我搜索了 Google 和 Whosebug,但找不到任何帮助,如果已经有人回答,我提前表示歉意。

谢谢。

要克隆没有子节点的节点,您可以像这样创建一个扩展方法:

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());

您可以为 return List

的 TreeView 创建扩展方法 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();

请记住在代码顶部的任何要使用的地方添加扩展的命名空间 class。

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

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

这是截图

这将创建一个新树,将所选节点作为根节点,其子节点仅包含标记为 "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 这样只会显示文件夹。当您的 IsHidingCalculations 计算结果为真时,您需要实施 ItemsStyle 并使用将项目 Visibility 设置为 Collapsed 的触发器。