Click here to Skip to main content
15,881,173 members
Articles / Programming Languages / C#
Article

Generic Tree Control

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
8 Feb 2009CPOL2 min read 25K   184   16   2
An article on a generic tree collection

Introduction

This article shows how to make a generic tree collection base and implement specific trees based on the tree collection. The abstract tree type implements IEnumerable<TreeNode<TNodeValue>>, ICollection<TreeNode<TNodeValue>>, IList<TreeNode<TNodeValue>>, IEnumerable, ICollection, IList, ISerializable. This gives you a number of  scenarios of usage.

Using the Code

Ok, here we go.

The example below creates a tree called BasicTree and lets it inherit from the base type Tree<TNodeValue>. We also create a node type for the tree called BasicNodeValue that inherits from the base type TreeNodeValue.

This is the only thing we need to get started using the tree collection functionality.

C#
public sealed class BasicTree : Tree<BasicNodeValue>
{
    public BasicTree(BasicNodeValue nodeValue)
        : base(nodeValue)
    {

    }
}

public sealed class BasicNodeValue : TreeNodeValue
{
    public BasicNodeValue()
        : base()
    {

    }

    public BasicNodeValue(String name, String path) :
        base(name, path)
    {

    }
}

Let's use the BasicTree further in the next code sample below:

Here we instantiate the BasicTree and manually populate the tree with nodes. Then we foreach all nodes in the tree collection and print out the path.

C#
//Instantiate the basic tree.
BasicTree tree = new BasicTree(new BasicNodeValue(@"Root", @"\"));

//Add the item 2 to the file basic tree root folder.
TreeNode<BasicNodeValue> parentNode1_2 = tree.AddLast
				(tree.RootNode, new BasicNodeValue(@"2", @"\2"));

//Add the item x to the item 2.
tree.AddLast(parentNode1_2, new BasicNodeValue(@"1", @"\2\1"));
tree.AddLast(parentNode1_2, new BasicNodeValue(@"2", @"\2\2"));
tree.AddLast(parentNode1_2, new BasicNodeValue(@"3", @"\2\3"));
tree.AddLast(parentNode1_2, new BasicNodeValue(@"4", @"\2\4"));

//Print the path of the basic items.
foreach (TreeNode<BasicNodeValue> basicItem in tree)
{
    String path = String.Format(@"{0}", basicItem.RelativePath);

    Console.WriteLine(path);
}

Ok, this wasn't quite so exciting perhaps? Let's take this a bit further.

In the example below (also included in the downloadable demo code) we instantiate two trees of type FileSystemTree and populate them manually (we can also build the index automatically by executing the tree.BuildIndex(); method). We have now created two trees that we can compare on whatever predicate we feel like. The example below compares to relative path but you can choose your own compare method, e.g. path combined with hash.

C#
//Instantiate the file system tree.
FileSystemTree tree = new FileSystemTree(new DirectoryInfo(@"C:\temp"));

//Add the folder 2 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode1_2 = tree.AddLast
	(tree.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2")));

//Add the folder x to the folder 2.
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\1")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\2")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\3")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\4")));

//Instantiate the file system tree.
FileSystemTree tree2 = new FileSystemTree(new DirectoryInfo(@"c:\temp2"));

//Add the folder 2 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode2_2 = tree2.AddLast
	(tree2.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\2")));

//Add the folder 3 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode2_3 = tree2.AddLast
	(tree2.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3")));

//Add the folder 4 to the folder 2.
tree2.AddLast(parentNode2_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\4")));

//Add the folder x to the folder 2.
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\1")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\2")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\3")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\4")));

//Compare the trees.
CompareTree<FileSystemNodeValue> resultTree = 
	tree.CompareTo(tree2, FileSystemTreeManager.Predicates.HasSameName());

foreach (TreeNode<CompareNodeValue<FileSystemNodeValue>> compareNode in resultTree)
{
    String result = String.Format(@"{0} {1}", 
	compareNode.RelativePath, compareNode.NodeValue.CompareResult);

    Console.WriteLine(result);
}

We can also execute a LINQ query on the tree:

C#
//Instantiate the file system tree.
FileSystemTree tree = new FileSystemTree(new DirectoryInfo(@"C:\temp"));

//Add the folder 2 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode1_2 = tree.AddLast
	(tree.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2")));

//Add the folder x to the folder 2.
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\1")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\2")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\3")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\4")));


var nodes = from TreeNode<FileSystemNodeValue> node in tree
            where node.Name == @"2" || node.Name == @"3"
            select node;

//Print the path of the file items.
foreach (TreeNode<FileSystemNodeValue> node in nodes)
{
    Console.WriteLine(String.Format(@"Name: {0}", node.Name));
}    

With the Tree<TNodeValue>, we can also execute an action on the nodes if a predicate is true. In the example below, we print out in the console how many nodes have the name '2':

C#
//Instantiate the file system tree.
FileSystemTree tree = new FileSystemTree(new DirectoryInfo(@"C:\temp"));

//Add the folder 2 to the file system tree root folder.
TreeNode<filesystemnodevalue /> parentNode1_2 = tree.AddLast
	(tree.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2")));

//Add the folder x to the folder 2.
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\1")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\2")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\3")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\4")));

List<filesystemnodevalue /> nodeValues = new List<filesystemnodevalue />();

tree.ActionIf(
    TreeManager<filesystemnodevalue />.Predicates.HasName(@"2", StringComparison.OrdinalIgnoreCase),
    TreeManager<filesystemnodevalue />.Actions.GetList(nodeValues), false);

Console.WriteLine(String.Format(@"Count: {0}", nodeValues.Count));

The last example below shows how to merge two trees:

C#
//Instantiate the file system tree.
FileSystemTree tree = new FileSystemTree(new DirectoryInfo(@"C:\temp"));

//Add the folder 2 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode1_2 = tree.AddLast
	(tree.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2")));

//Add the folder 1 to the folder 2.
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\1")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\2")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\3")));
tree.AddLast(parentNode1_2, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp\2\4")));

//Instantiate the file system tree.
FileSystemTree tree2 = new FileSystemTree(new DirectoryInfo(@"c:\temp2"));

//Add the folder 2 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode2_2 = tree2.AddLast
	(tree2.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\2")));

//Add the folder 3 to the file system tree root folder.
TreeNode<FileSystemNodeValue> parentNode2_3 = tree2.AddLast
	(tree2.RootNode, new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3")));

//Add the folder x to the folder 2.
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\1")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\2")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\3")));
tree2.AddLast(parentNode2_3, 
	new FileSystemNodeValue(new DirectoryInfo(@"C:\temp2\3\4")));

//Merge the trees.
Tree<FileSystemNodeValue> mergedTree = tree.Merge(tree2);

foreach (TreeNode<FileSystemNodeValue> mergedNode in mergedTree)
{
    String result = String.Format(@"{0}", mergedNode.RelativePath);

    Console.WriteLine(result);
}

Points of Interest

All code in the article is provided in the demo. If you find anything interesting or have some great ideas of how to improve the code, please send me a note!

May the source be with you! ;)

History

  • 2009-02-07 Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) B3IT
Sweden Sweden
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralConfusing Title Pin
GLLNS9-Feb-09 8:08
GLLNS9-Feb-09 8:08 
Generic Tree Control or Generic Tree Collection ?!
GeneralRe: Confusing Title Pin
Martin Dahlstedt9-Feb-09 9:36
Martin Dahlstedt9-Feb-09 9:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.