Table of Contents

Tree View

TreeView is a control for navigating hierarchical objects. It comes in two forms TreeView and TreeView<T>.

TreeView API Reference

Using TreeView

The basic non generic TreeView class is populated by ITreeNode objects. The simplest tree you can make would look something like:

var tree = new TreeView()
{
  X = 0,
  Y = 0,
  Width = 40,
  Height = 20
};

var root1 = new TreeNode("Root1");
root1.Children.Add(new TreeNode("Child1.1"));
root1.Children.Add(new TreeNode("Child1.2"));

var root2 = new TreeNode("Root2");
root2.Children.Add(new TreeNode("Child2.1"));
root2.Children.Add(new TreeNode("Child2.2"));

tree.AddObject(root1);
tree.AddObject(root2);

Having to create a bunch of TreeNode objects can be a pain especially if you already have your own objects e.g. House, Room etc. There are two ways to use your own classes without having to create nodes manually. Firstly you can implement the ITreeNode interface:

// Your data class
private class House : TreeNode {

    // Your properties
    public string Address {get;set;}
    public List<Room> Rooms {get;set;}

    // ITreeNode member:
    public override IList<ITreeNode> Children => Rooms.Cast<ITreeNode>().ToList();

    public override string Text { get => Address; set => Address = value; }
}


// Your other data class
private class Room : TreeNode{

    public string Name {get;set;}

    public override string Text{get=>Name;set{Name=value;}}
}

After implementing the interface you can add your objects directly to the tree


var myHouse = new House()
{
    Address = "23 Nowhere Street",
    Rooms = new List<Room>{
      new Room(){Name = "Ballroom"},
      new Room(){Name = "Bedroom 1"},
      new Room(){Name = "Bedroom 2"}
    }
};

var tree = new TreeView()
{
    X = 0,
    Y = 0,
    Width = 40,
    Height = 20
};

tree.AddObject(myHouse);

Alternatively you can simply tell the tree how the objects relate to one another by implementing ITreeBuilder<T>. This is a good option if you don't have control of the data objects you are working with.

TreeView<T>

The generic Treeview<T> allows you to store any object hierarchy where nodes implement Type T. For example if you are working with DirectoryInfo and FileInfo objects then you could create a TreeView<FileSystemInfo>. If you don't have a shared interface/base class for all nodes you can still declare a TreeView<object>.

In order to use TreeView<T> you need to tell the tree how objects relate to one another (who are children of who). To do this you must provide an ITreeBuilder<T>.

Implementing ITreeBuilder<T>

Consider a simple data model that already exists in your program:

private abstract class GameObject
{

}

private class Army : GameObject
{
    public string Designation {get;set;}
    public List<Unit> Units {get;set;}


    public override string ToString ()
    {
        return Designation;
    }
}

private class Unit : GameObject
{
    public string Name {get;set;}
    public override string ToString ()
    {
        return Name;
    }
}

An ITreeBuilder<T> for these classes might look like:


private class GameObjectTreeBuilder : ITreeBuilder<GameObject> {
    public bool SupportsCanExpand => true;

    public bool CanExpand (GameObject model)
    {
        return model is Army;
    }

    public IEnumerable<GameObject> GetChildren (GameObject model)
    {
        if(model is Army a)
            return a.Units;

        return Enumerable.Empty<GameObject>();
    }
}

To use the builder in a tree you would use:

var army1 = new Army()
{
    Designation = "3rd Infantry",
    Units = new List<Unit>{
        new Unit(){Name = "Orc"},
        new Unit(){Name = "Troll"},
        new Unit(){Name = "Goblin"},
    }
};

var tree = new TreeView<GameObject>()
{
    X = 0,
    Y = 0,
    Width = 40,
    Height = 20,
    TreeBuilder = new GameObjectTreeBuilder()
};


tree.AddObject(army1);

Alternatively you can use DelegateTreeBuilder<T> instead of implementing your own ITreeBuilder<T>. For example:

tree.TreeBuilder = new DelegateTreeBuilder<GameObject>(
    (o)=>o is Army a ? a.Units 
      : Enumerable.Empty<GameObject>());

Node Text and ToString

The default behavior of TreeView is to use the ToString method on the objects for rendering. You can customise this by changing the AspectGetter. For example:

treeViewFiles.AspectGetter = (f)=>f.FullName;