0

Hello I currently have a TreeView with the following structure:

  • Root
  • Child

    • Root
      • Child
        • Root
        • Child
        • Child
          • RootN
          • ChildN

    The TreeView structure can basically have NRootNodes - NChildren and the NRootNodes can have NRoots and NChildren so basically just like Windows Explorer Window.

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:

  • Root
    • Root
      • Root
        • Root
          • Root

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.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
darksleep
  • 346
  • 1
  • 6
  • 13
  • -Do you mean, you want to get Folders only? -Result would be List ot tree? – Reza Aghaei Sep 02 '15 at 07:13
  • Yes Reza, I want to get the Folders only, and it should be a List – darksleep Sep 02 '15 at 07:15
  • Of what i understood, you need to verify the "Tag" property whether the item is a "Folder" or a "Calculation". And because you want the tree to have a new structure you need to copy the original tree and the remove the child nodes "Calculation" from the copy. – BionicCode Sep 02 '15 at 07:23
  • @BionicCode - true on that, but somehow I cannot remove the Childs. I basically have a SelectedNode that contains all of it's structure including Folders and Childs etc. Somehow I need to iterate through that SelectedNode and remove all the Childs so in the end I will have only Folders. – darksleep Sep 02 '15 at 07:26
  • So your new tree starts from SelectedNode ignoring the parent tree? – BionicCode Sep 02 '15 at 07:27
  • @BionicCode - the new TreeStards from SelectedNode and going downwards, containing all of the Roots without the Childs. Basically a strucutre only containing Roots. – darksleep Sep 02 '15 at 07:29
  • I don't know your implementation details like your templates. But you could add a property that is bound to the Visibility property of the item. This way you could just hide the child nodes so they wont display. Or going the way to copy your tree's ItemsSource and remove the child nodes you don't like. If this is what you like and you dunno how to do i'll try to give an aexample – BionicCode Sep 02 '15 at 07:32
  • I provided an example (check my answer). I hope it meets your requirements... – BionicCode Sep 02 '15 at 09:18

3 Answers3

2

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

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
1

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.

BionicCode
  • 1
  • 4
  • 28
  • 44
  • thank you for your solution. Your algorithm has solved the problem, in the end I get one TreeNode that has chained all the other nodes ( only the Parents ). – darksleep Sep 02 '15 at 11:19
  • @BionicCode I have posted my extension method approach to get all nodes of a tree as List here http://stackoverflow.com/a/32360956/3110834 it will be appreciated if you take a look at that and find it helpful:) – Reza Aghaei Sep 02 '15 at 18:55
  • @Reza Aghaei It's clean, I like it. But the algorithm will flatten the tree and he wanted to keep the original hierarchical structure. So I think it won't help in this case. – BionicCode Sep 03 '15 at 15:31
0

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());
György Kőszeg
  • 17,093
  • 6
  • 37
  • 65