darksleep
darksleep

Reputation: 346

Remove Child Nodes from Parent Node

Hello I currently have a TreeView with the following structure:

My current issue that I have is that I have to get all the Parents or Root, in this case Roots / RootN and then I have to Remove all of their Child Nodes, in this case Child / ChildN. In the end I have to have only the Parent Nodes and then Clone them so I can move them to a different location within the TreeView.

RootNodes have a unique Tag - Folder and ChildNodes have another unique Tag - Calculations, as I have said earlier, I have to get rid of all Calculations in the Selected Node so only the Structure of that Selected Node will Remain.

Basically in the end I have to have something like this:

I have a recursive method that "scans" the SelectedNode and gets all the 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;
    }

In the end I have a List that will hold all the Parents but the problem I'm facing is that that Parents also contain their descendents, in this case the Calculations

I have searched Google and StackOverFlow but I could not find anything of help, I appologize in advance if this has already been answered.

Thank you.

Upvotes: 0

Views: 6814

Answers (3)

Reza Aghaei
Reza Aghaei

Reputation: 125217

You can create an extension method GetAllNodes for TreeView that return List

Remember using using System.Linq; at top of your code

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

And the usage will be:

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

Remember to add namespace of your extensions class at top of your code wherever you want to use it.

As an example you can set All nodes with tag of Folder to be in Red forecolor:

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

And here is an Screenshot

enter image description here

Upvotes: 2

BionicCode
BionicCode

Reputation: 28988

This will create a new tree with the selected node as root and which child nodes consists only of nodes that are tagged "Folder".
You need to create a copy constructor (or extension method) to deep copy the node to prevent the manipulation on the node objects to impact your original tree source:

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

I think this should do it, but I didn't tested it. But maybe at least the idea behind it is clear.

But as I mentioned before, maybe it's better to traverse the tree (using same ItemsSource) and set a property (e.g. IsHidingCalculations) to true so that only the folders will show up. You would need to implement an ItemsStyle and use a trigger that sets the items Visibility to Collapsed when your IsHidingCalculations evaluates to true.

Upvotes: 1

Gy&#246;rgy Kőszeg
Gy&#246;rgy Kőszeg

Reputation: 18013

To clone a node without its children you can create an extension method like this:

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

and then:

collectedNodes.Add(node.CloneWithoutChildren());

Upvotes: 0

Related Questions