Article: A simple TreeView experiment

Home Page


Consultancy

  • Service Vouchers
  • Escrow Service

Shop



Programming
  • Articles
  • Tools
  • Links

Search

 

Contact

 

Chess Puzzles




DWHS

Valid XHTML 1.0 Transitional
Valid CSS!
Mobile-friendly!

Simply adding some nodes hierarchically to a TreeView control.

category 'experiment', language C#, created 12-Aug-2009, version V1.2 (04-Dec-2009), by Luc Pattyn


License: The author hereby grants you a worldwide, non-exclusive license to use and redistribute the files and the source code in the article in any way you see fit, provided you keep the copyright notice in place; when code modifications are applied, the notice must reflect that. The author retains copyright to the article, you may not republish or otherwise make available the article, in whole or in part, without the prior written consent of the author.

Disclaimer: This work is provided “as is”, without any express or implied warranties or conditions or guarantees. You, the user, assume all risk in its use. In no event will the author be liable to you on any legal theory for any special, incidental, consequential, punitive or exemplary damages arising out of this license or the use of the work or otherwise.


I hadn't used the standard TreeView Control yet, so I decided to perform a little test with it. I don't use tree views that often, and when I do I tend to need lots of extra functionality and roll my own Control.

TreeView Experiment

Program structure

The environment used is the Microsoft .NET Framework (version 2.0 or above) and the C# programming language. The nodes to be displayed are taken from a simple text file:

root
root/folder1
root/folder2
root/folder2/subfolder1
root/folder2/subfolder2/subfolder3
root/folder3/subfolder4
root/folder4

This is the bulk of the code; the heart of the matter is the AddPath() method which contains a foreach loop to process the individual parts of each path:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace TreeView1 {
	public class Form1 : Form {
		public Form1() {
			InitializeComponent();
			Size=new Size(SystemInformation.PrimaryMonitorSize.Width-150,
				SystemInformation.PrimaryMonitorSize.Height-50);
		}

		private void log(string s) {
			lb.Items.Add(s);
			lb.TopIndex=lb.Items.Count-1;
		}

		private void log(Exception exc) {
			foreach(string s in exc.ToString().Split('\n','\r')) if (s.Length!=0) log(s);
		}

		private void Form1_Shown(object sender, EventArgs e) {
			try {
				string[] paths=File.ReadAllLines("paths.txt");
				int count=0;
				foreach (string path in paths) AddPath(path, ref count);
				tv.ExpandAll();
				log("========================== Done (created "+count+" nodes)");
			} catch (Exception exc) { log(exc); }
		}

		private void AddPath(string path, ref int count) {
			log("========================== creating "+path);
			TreeNodeCollection nodes=tv.Nodes;
			foreach (string nodeName in path.Split('/')) {
				log("nodeName="+nodeName);
				TreeNode found;
				if (nodes.ContainsKey(nodeName)) {
					found=nodes.Find(nodeName, false)[0];
				} else {
					count++;
					found=nodes.Add(nodeName);
					found.Name=nodeName;		// find() looks for Name, not Text
					log("added node "+nodeName);
				}
				nodes=found.Nodes;
			}
		}
	}
}

And here is the designer-generated code which has to be added to the above to set up the GUI; a ListBox is used for logging, as I often do:

		private void InitializeComponent() {
			this.tv = new System.Windows.Forms.TreeView();
			this.lb = new System.Windows.Forms.ListBox();
			this.SuspendLayout();
			// 
			// tv
			// 
			this.tv.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top
				| System.Windows.Forms.AnchorStyles.Bottom)  | System.Windows.Forms.AnchorStyles.Left)));
			this.tv.Location = new System.Drawing.Point(34, 19);
			this.tv.Name = "tv";
			this.tv.Size = new System.Drawing.Size(369, 341);
			this.tv.TabIndex = 0;
			// 
			// lb
			// 
			this.lb.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top
				| System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.lb.FormattingEnabled = true;
			this.lb.Location = new System.Drawing.Point(441, 18);
			this.lb.Name = "lb";
			this.lb.Size = new System.Drawing.Size(409, 342);
			this.lb.TabIndex = 1;
			// 
			// Form1
			// 
			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
			this.ClientSize = new System.Drawing.Size(863, 384);
			this.Controls.Add(this.lb);
			this.Controls.Add(this.tv);
			this.Name = "Form1";
			this.Text = "TreeView Experiment";
			this.Shown += new System.EventHandler(this.Form1_Shown);
			this.ResumeLayout(false);
		}

		private System.Windows.Forms.TreeView tv;
		private System.Windows.Forms.ListBox lb;

Storing non-string items

A TreeView differs from other list oriented Controls such as ListBox and ComboBox in that it holds items ("nodes") in a hierarchical way, which implies each node needs the capability to hold a collection of child nodes. The net result is a TreeView only accepts TreeNode instances, which can be created explicitly or implicitly.

When the nodes in a TreeView should hold more information than just a display string, there basically are two ways to store user-defined nodes (e.g. instances of MyTreeNode):

  1. use regular TreeNode instances, and store a reference to your own MyTreeNode in the TreeNode.Tag property, which is available for any use one sees fit; this works whatever the definition of MyTreeNode is but requires you to write myTreeView.Nodes[i].Tag to get at your extra information;
  2. or make sure MyTreeNode inherits from TreeNode; the advantage is the Tag property isn't used at all, however this is feasible only when no other inheritance is required as C# (or VB.NET) don't support multiple inheritance.

In both cases the TreeNode needs its Text property set to the display text; as well as its Name property if you want the Find() method to work. Overriding the ToString() method does not change that.

Conclusion

Nothing special to report, it works as expected.

History

  • Version 1.0 (12-Aug-2009): Original version
  • Version 1.1 (13-Aug-2009): Minor edits
  • Version 1.2 (04-Dec-2009): Added "Storing non-string items" chapter


Perceler

Copyright © 2012, Luc Pattyn

Last Modified 02-Sep-2013