tags:

views:

584

answers:

6

This is a System.Windows.Forms.TreeView, not a WPF or Web TreeView.

I must be missing something, because I can't believe this is that difficult.

I've got a TreeView on my form. Loading all the data to populate the TreeView is very slow, so I want to load just the top-level nodes and then fill in the children as the user expands nodes. The problem is, if a node doesn't have any children it doesn't display the + sign next to the node, which means it can't be expanded, which means I can't capture an Expanding event to load the children.

Years ago when I was using PowerBuilder you would set a HasChildren (or similar) property to true to essentially 'lie' to the control and force it to display the + and you could then capture the Expanding event. I've not been able to figure out how to force a + to appear on a node when there are no child nodes.

I've tried an approach where I add a dummy node to each node and then on expanding check if the dummy node is present and remove it then load the children, but for various reasons that aren't worth getting into here that solution is not viable in my situation.

I've Googled for various combinations of c#, treeview, delayed, deferred, load, force, expansion, and a few other terms that escape me now with no luck.

P.S. I found the TreeViewAdv project on SourceForge, but I'd rather not introduce a new component into our environment if I can avoid it.

A: 

A possible solution is to stay one step ahead of the treeview:

private void Form1_Load(object sender, EventArgs e)
{
 // initialise the tree here
 var nodeSomething = treeView1.Nodes.Add("Something");
 nodeSomething.Nodes.Add("Something below something");

 treeView1.AfterExpand += AfterExpand;
}

private void AfterExpand(object sender, TreeViewEventArgs e)
{
 foreach (TreeNode node in e.Node.Nodes)
 {
  // skip if we have already loaded data for this node
  if (node.Tag != null) 
   continue;
  node.Tag = new object();
  node.Nodes.AddRange(GetDataForThisNode(node));
 }
}
Dries Van Hansewijck
A: 

I've also wondered how to get the + to show up next to childless nodes, but I never found a good way. My solution was to handle the MouseDoubleClick event like so:

Private Sub tvwMain_MouseDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles tvwMain.MouseDoubleClick
    Dim oNode As TreeNode

    oNode = tvwMain.GetNodeAt(e.X, e.Y)

    If oNode IsNot Nothing Then
        If oNode.Nodes.Count = 0 Then
            'add children here
        End If
    End If
End Sub
Chris Tybur
A: 

I agree with Chris, I've had to do this vary thing. Load the top nodes and then capture the click event, make sure the click was on a selected node, and then populate the node, and then finally expand it.

If it's required to have the plus, then load the top nodes and drop a dummy node in it. Make sure you capture the click or expand event, clear the nodes and then repopulate it.

Joshua Belden
I second the dummy node idea. I'm using that myself and setting the Tag property to a specific value to differentiate the "Loading..." dummy nodes from the others. In BeforeExpand, I check for the existence of the dummy node and replace the contents. It works well for me.
X-Cubed
A: 

Have you tried enclosing your node additions in BeginUpdate()and EndUpdate() calls? This disables any painting and as such allows you to add a large number of nodes to the TreeView without as significant delays.

MSDN: TreeView.BeginUpdate Method

CMerat
i think the OP meant that loading the data itself (from DB, for example) was slow, not adding the tree nodes, so they want to load the data on-demand (when user expands each tree node).
Lucas
Lucas comment is correct. The TreeView itself populates fast enough, it's getting the data that is slow.
Craig W.
+1  A: 

Load the first 2 levels at startup and load 2 levels down when a node is expanded.

M. Jahedbozorgan
A: 

You may have better luck using TreeViewAdv (on sourceforge).

leppie