tags:

views:

741

answers:

2

I need to construct a huge treeview from a composite database table with Grouping.

Grouping is, what we see in SQL Server Management Studio Express. After a Database node, some fixed folders are shown (like, Database Diagrams, Tables, Views, Synonyms, Programmability and Security) and children are grouped in those folders.

Up to this point I have used AfterSelect event and handler to achieve this.

But the problem with AfterSelect is, before selecting the node, the viewer is not able to know whether there is any child available. This is because, the expandable plus sign is not visible.

I want to use BeforeExpand. But the problem with BeforeExpand is, it works if the children are already populated. In that case, when I click groups, nothing happens.

How to solve this?

So codes/web-link will be appreciated.

A: 

It's standard behaviour for a tree to show a "+" in front of every folder/group, and the plus dissapears when clicked on if it's found to have no children, this saves the expensive "do you have children" check.

Alternatively you can provide this information if you have a cheap way of determining if a node has children. This question provides more information.

Timothy Walters
+4  A: 

What I usually do is to add a "dummy child node" wherever there may be children that should be loaded in a lazy manner. This will make the parent have the plus sign, and then you can add code to the AfterExpand event where you do the following:

  • Check if there are are exactly one child, and if that child is the dummy node (you can use the Tag property to identify the dummy node)
  • If the dummy node is found, launch a search to get the children and add them to the parent node, finish it off by removing the dummy node.

I typically give the dummy node a text like "Loading data. Please wait..." or so, so that the user gets some info on what is going on.

Update
I put together a simple example:

public class TreeViewSample : Form
{
    private TreeView _treeView;
    public TreeViewSample()
    {
        this._treeView = new System.Windows.Forms.TreeView();
        this._treeView.Location = new System.Drawing.Point(12, 12);
        this._treeView.Size = new System.Drawing.Size(200, 400);
        this._treeView.AfterExpand +=
            new TreeViewEventHandler(TreeView_AfterExpand);
        this.ClientSize = new System.Drawing.Size(224, 424);
        this.Controls.Add(this._treeView);
        this.Text = "TreeView Lazy Load Sample";
        InitializeTreeView();
    }

    void TreeView_AfterExpand(object sender, TreeViewEventArgs e)
    {
        if (e.Node.Nodes.Count == 1 && e.Node.Nodes[0].Tag == "dummy")
        {
            // this node has not yet been populated, launch a thread
            // to get the data
            ThreadPool.QueueUserWorkItem(state =>
            {
                IEnumerable<SomeClass> childItems = GetData();
                // load the data into the tree view (on the UI thread)
                _treeView.BeginInvoke((Action)delegate
                {
                    PopulateChildren(e.Node, childItems);
                });
            });
        }
    }

    private void PopulateChildren(TreeNode parent, IEnumerable<SomeClass> childItems)
    {
        TreeNode child;
        TreeNode dummy;
        TreeNode originalDummyItem = parent.Nodes[0];
        foreach (var item in childItems)
        {
            child = new TreeNode(item.Text);
            dummy = new TreeNode("Loading. Please wait...");
            dummy.Tag = "dummy";
            child.Nodes.Add(dummy);
            parent.Nodes.Add(child);
        }
        originalDummyItem.Remove();
    }

    private IEnumerable<SomeClass> GetData()
    {
        // simulate that this takes some time
        Thread.Sleep(500);
        return new List<SomeClass>
        {
            new SomeClass{Text = "One"},
            new SomeClass{Text = "Two"},
            new SomeClass{Text = "Three"}
        };
    }

    private void InitializeTreeView()
    {
        TreeNode rootNode = new TreeNode("Root");
        TreeNode dummyNode = new TreeNode("Loading. Please wait...");
        dummyNode.Tag = "dummy";
        rootNode.Nodes.Add(dummyNode);
        _treeView.Nodes.Add(rootNode);
    }
}

public class SomeClass
{
    public string Text { get; set; }
}
Fredrik Mörk