ScottishTapWater
ScottishTapWater

Reputation: 4846

Populating TreeView From Object

I have a fairly simple class structure where there are Graphic objects, each contains a List<Symbol> and each Symbol contains a List<Alias>: amgonst their other properties.

The obvious way (and my current method) is to use nested foreach loops to generate the nodes and to populate the tree view (this actually works fine) like below:

    public void ToTree(TreeView treeControl)
    {
        treeControl.Nodes.Clear();
        List<TreeNode> graphicsNodes = new List<TreeNode>();
        foreach (Graphic graphic in Graphics)
        {
            List<TreeNode> symbolNodes = new List<TreeNode>();
            foreach (Symbol symbol in graphic.Symbols)
            {
                List<TreeNode> aliasNodes = new List<TreeNode>();
                foreach (Alias alias in symbol.Aliases)
                {
                    aliasNodes.Add(new TreeNode(alias.AliasName + ": " + alias.AliasValue));
                }
                symbolNodes.Add(new TreeNode(symbol.SymbolName, aliasNodes.ToArray()));
            }
            graphicsNodes.Add(new TreeNode(graphic.FileName, symbolNodes.ToArray()));
        }
        treeControl.Nodes.AddRange(graphicsNodes.ToArray());
    }

However, I'm curious if there is anything that I can implement in my class, or any methods that I can overload so that I can simply do something similar to treeView.Nodes.Add(graphic).

Ideally, this would allow for me to determine which object is being clicked on with the NodeClickEvent rather than me having to take the node's text and then perform a search separately.

This is so that I would have direct access to the fields and members of each object from within that node, making it much easier to modify properties from the TreeView click events.

Upvotes: 4

Views: 2575

Answers (1)

rene
rene

Reputation: 42494

What you can do is create subclasses of TreeNode that accept your classes in their constructor. You can then have each subclass implement the specific handling for that type. I looked into the suggestion from Hans to do something useful with the TreeNodeCollection but this class has no public constructor so I couldn't figure out how that should work.

A simple implementation looks like this for your three classes I distilled from your example:

Graphic and GraphicNode

public class GraphicNode:TreeNode
{ 
    // takes a Graphic instance
    public GraphicNode(Graphic grp)
    {
        // how do you want to represent it
        this.Text = grp.FileName;
        // and this class 'knows' how to handle its children
        Nodes.AddRange(grp.Symbols.Select(s => new SymbolNode(s)).ToArray());
    }
}

Symbol and SymbolNode

public class SymbolNode:TreeNode
{
    public SymbolNode(Symbol sym)
    {
        this.Text = sym.SymbolName;
        Nodes.AddRange(sym.Aliases.Select(ali => new AliasesNode(ali)).ToArray());
    }
}

Alias and AliasNode

Notice how this class implements a public Click method. You can leverage that from an NodeMouseClick event.

public class AliasesNode:TreeNode
{
    public AliasesNode(Aliases al)
    {
        this.Text = String.Format("{0} - {1}", al.AliasName, al.AliasValue);   
    }

    public void Click()
    {
        MessageBox.Show(new String(this.Text.Reverse().ToArray()));
    }                
}

Populate the Treeview

The following code populates the Treeview by adding the GraphicNodes. By callimg BeginUpdate first, we prevent that the control draws its content on every node that is added. Don't forget to call EndUpdate so the control layouts and redraws all newly added nodes. Notice that you only need to add the GraphicNodes here, the adding of the other nodes is handled by the subclassed TreeNodes.

// tell the control to hold its paint/redraw events until 
// we're done adding all items
tv.BeginUpdate();
foreach(var g in graphics)
{
    tv.Nodes.Add(new GraphicNode(g));
}
// done, draw all nodes now
tv.EndUpdate();

If you wire up the NodeMouseClick to the following event handler you can reach into the specific implementation of the TreeNode:

private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
    var node = e.Node as AliasesNode;
    if (node != null)
    {
        node.Click();
    }
}

When we click an AliasTreenode we should see the MessageBox popup that is implemented in the Click method of that class:

tree view click node

Upvotes: 5

Related Questions