Populating a TreeView in Windows forms

Hi.
I want to make a TreeView like in Windows Explorer. How does one go about populating that tree, putting nodes in it and making it like the TreeView in Windows Explorer?
SnertillAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

dbtothCommented:
Treeviews are a collection of nodes, specifically TreeNode objects.

Although you see the documentation talk about root nodes, parent nodes, child nodes, etc... in reality these are all just the same TreeNode object. What gives a TreeNode is different characteristics depends on exactly where in the Tree structure your TreeNode lives.

Here's a sample layout

Baked Goods
  |- Cookies
  |    |-Choc Chip
  |    |-Oatmeal Raisin
  |- Muffins
  |    |-Blueberry
  |    |-Bran
-Drinks
  |- Coffee
  |- Milk
  |    |-White
  |    |-Chocolate


Here's a little fragment that would have created this tree.. how this works will make more sense in a minute. Most people add their treeviews at design time, so to follow along, start a new windows form project and drag a treeview into it. Change the name from treeView1 to just tv

Now, in your public Form1() after the

//
// TODO: Add any constructor code after InitializeComponent call
//

put these lines
      tv.Nodes.Add("Baked Goods");
      tv.Nodes.Add("Drinks");
      tv.Nodes[0].Nodes.Add("Cookies");
      tv.Nodes[0].Nodes.Add("Muffins");
      tv.Nodes[0].Nodes[0].Nodes.Add("Choc Chip");
      tv.Nodes[0].Nodes[0].Nodes.Add("Oatmeal Raisin");
      tv.Nodes[0].Nodes[1].Nodes.Add("Blueberry");
      tv.Nodes[0].Nodes[1].Nodes.Add("Bran");
      tv.Nodes[1].Nodes.Add("Coffee");
      tv.Nodes[1].Nodes.Add("Milk");
      tv.Nodes[1].Nodes[1].Nodes.Add("White");
      tv.Nodes[1].Nodes[1].Nodes.Add("Chocolate");

If the TreeNode has no parent node, then this is a Root TreeNode (one of the base nodes that started your tree) In the above example, Baked Goods and Drinks are both Root Treenodes. You can tell from the above code, as you will notice that the code to add them was:

      tv.Nodes.Add("Baked Goods");
      tv.Nodes.Add("Drinks");

tv.Nodes is the collection of TreeNodes for the Treeview tv. These nodes are indexed according to their creation order. As such tv.Nodes[0] would be the TreeNode for Baked Goods and tv.Nodes[1] would be the TreeNode for Drinks.

So that's straightforward, the Nodes collection of the Treeview control contains all the root nodes... but how do you get add the child nodes. Simple, every TreeNode is allowed it's own collection of subnodes. so to add Cookies and Muffins to the Baked good nodes, we start by specifying the Baked goods node, which is tv.Nodes[0], then access it's Node object tv.Nodes[0].Nodes, and then the method we are using Add

      tv.Nodes[0].Nodes.Add("Cookies");
      tv.Nodes[0].Nodes.Add("Muffins");

Because Cookies and Muffins are added to an existing node, these are Child nodes.

We can continue this process pretty much indefinitely, so to add cookie flavours, we grab Baked Goods ,tv.Nodes[0], then it's Cookie child, tv.Nodes[0].Nodes[0], then add to that node collection

      tv.Nodes[0].Nodes[0].Nodes.Add("Choc Chip");
      tv.Nodes[0].Nodes[0].Nodes.Add("Oatmeal Raisin");

We can do the same with Muffins, but because Muffins were our second Baked good node, we remember to change the index element. We're still using Baked Goods (tv.Nodes[0]) but we've moved to the second child of Baked Goods (tv.Nodes[0].Nodes[1]) so that the muffin flavours end up in the proper spot

      tv.Nodes[0].Nodes[1].Nodes.Add("Blueberry");
      tv.Nodes[0].Nodes[1].Nodes.Add("Bran");

Sometimes it's clearer to do something like this:

      TreeNode rootTN = tv.Nodes[0]; // Select the Baked Goods
      TreeNode parentTN = rootTN.Nodes[0]; // Select the Cookies Node
      parentTN.Nodes.Add("Choc Chip");

Note that this is 100% equivalent to:

      tv.Nodes[0].Nodes[0].Nodes.Add("Choc Chip");

It's just a little easier to read.

Where using the longer method also helps is if you want something like this:

Baked Goods
  |- Cookies
  |    |- Choc Chip Cookies
  |    |-Oatmeal Raisin Cookies

Where you want the parents name to be included in the name of the child. This could be done long hand, by manually inserting the text, but you could also do this:

      TreeNode rootTN = tv.Nodes[0]; // Select the Baked Goods
      TreeNode parentTN = rootTN.Nodes[0]; // Select the Cookies Node
      parentTN.Nodes.Add("Choc Chip" + parentTN.Text);

This would append the name of the parent to the manually supplied text for the child node you are creating. Note that we didn't do anything with the Choc Chip node, but the Add method actually returns the TreeNode of the node we just created. So if u wanted to manipulate the node you could do so, for example, if we wanted to make sure our new child node was visible in the tree, expanding links or scrolling the tree as necessary, we could use the EnsureVisible() method on the node we create

      TreeNode rootTN = tv.Nodes[0]; // Select the Baked Goods
      TreeNode parentTN = rootTN.Nodes[0]; // Select the Cookies Node
      TreeNode childTN = parentTN.Nodes.Add("Choc Chip" + parentTN.Text);
      childTN.EnsureVisible();

It's also possible to create a new node in advance, and add that node to the tree. For example, to add the Oatmeal Raisin cookie to the above:

      TreeNode rootTN = tv.Nodes[0]; // Select the Baked Goods
      TreeNode parentTN = rootTN.Nodes[0]; // Select the Cookies Node
      TreeNode childTN = parentTN.Nodes.Add("Choc Chip" + parentTN.Text);

      TreeNode childTN2 = new TreeNode();
      childTN2.Text = "Oatmeal Raisin " + parentTN.Text;
      TreeNode secondChildTN = parentTN.Nodes.Add(childTN2);
      secondChildTN.EnsureVisible();

The nice part about this relationship between nodes is that you can navigate up and down the tree. So lets say someone clicked on your Cookies node, you can find it's parent or children easily:


      TreeNode selTN = tv.SelectedNode();
      
Parent would be selTN.Parent, the children of the node (which gives you the node collection) would be selTN.Nodes. A common thing would be to expand the node automatically if a parent is clicked

private void tv_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
      TreeNode selTN = tv.SelectedNode;
      if (selTN.Nodes.Count > 0)
      {
            TreeNode firstChildTN = selTN.Nodes[0];
            firstChildTN.EnsureVisible();
      }
                        
}


Note that you could have just selTN.Nodes[0].EnsureVisible(); which does the same thing and saves having to declare TreeNode firstChildTN

I hope that gives you enough insight into Treeviews to get you started. For a functional example, try this.. it will populate a treeview with all the directories starting at a specified path.

public Form1()
{
      //
      // Required for Windows Form Designer support
      //
      InitializeComponent();

      //
      // TODO: Add any constructor code after InitializeComponent call
      //

      TreeNode curNode = tv.Nodes.Add(@"C:\Tools");

      string[] dirs = Directory.GetDirectories(@"c:\Tools");
      foreach (string dir in dirs)
      {
            ParseDir(dir, curNode);
      }
}

private void ParseDir(string srcDir, TreeNode curTN)
{
      string dirLeaf = srcDir.Substring(srcDir.LastIndexOf(@"\")+1);
      TreeNode newTN = curTN.Nodes.Add(dirLeaf);
      string[] dirs = Directory.GetDirectories(srcDir);
      if (dirs.Length > 0)
      {
            foreach (string subDir in dirs)
            {
                  ParseDir(subDir, newTN);
            }
      }
}

To see it in action, wire the following event (which is the default event if you double-click the treeview in design mode)

private void tv_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
      TreeNode selTN = tv.SelectedNode;
      MessageBox.Show(selTN.FullPath);      
}

this will show you the full path to the node that you clicked.
0
dbtothCommented:
To also see files in the above example, change ParseDir:

private void ParseDir(string srcDir, TreeNode curTN)
{
      string dirLeaf = srcDir.Substring(srcDir.LastIndexOf(@"\")+1);
      TreeNode newTN = curTN.Nodes.Add(dirLeaf);
      string[] dirs = Directory.GetDirectories(srcDir);
      if (dirs.Length > 0)
      {
            foreach (string subDir in dirs)
            {
                  ParseDir(subDir, newTN);
            }
      }
      else
      {
            // Get some files
            string[] files = Directory.GetFiles(srcDir);
            foreach (string file in files)
            {
                  string fileLeaf = file.Substring(file.LastIndexOf(@"\")+1);
                  newTN.Nodes.Add(fileLeaf + " (file)");
            }
      }
}

Note that nodes are allowed to have images, so you could put an image of a folder beside your folders, and a file icon beside the file, it just takes a little more work. Take a look at the ImageList property of TreeView to get an idea how to do this.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.