TreeView Control
The treeView control displays nodes hierarchically in a tree. Traditionally, nodes are objects that contain values and can refer to other nodes. A parent node contains child nodes, and the child nodes can be parents to other nodes. Two child nodes that have the same parent node are considered sibling nodes. A tree is a collection of nodes, usually organized in a hierarchical manner. The first parent node of a tree is the root node (a treeView can have multiple roots). For example, the file system of a computer can be represented as a tree. The top-level directory (perhaps C:) would be the root, each subfolder of C: would be a child node and each child folder could have its own children. TReeView controls are useful for displaying hierarchal information, such as the file structure that we just mentioned. We cover nodes and trees in greater detail in Chapter 25, Data Structures. Figure 14.24 displays a sample treeView control on a Form.
Figure 14.24. TReeView displaying a sample tree.
A parent node can be expanded or collapsed by clicking the plus box or minus box to its left. Nodes without children do not have these boxes.
The nodes in a treeView are instances of class treeNode. Each TReeNode has a Nodes collection (type treeNodeCollection), which contains a list of other treeNodesknown as its children. The Parent property returns a reference to the parent node (or null if the node is a root node). Figure 14.25 and Fig. 14.26 list the common properties of treeViews and TReeNodes, common treeNode methods and a common TReeView event.
treeView properties and an event |
Description |
---|---|
Common Properties |
|
CheckBoxes |
Indicates whether CheckBoxes appear next to nodes. A value of TRue displays CheckBoxes. The default value is false. |
ImageList |
Specifies an ImageList object containing the node icons. An ImageList object is a collection that contains Image objects. |
Nodes |
Lists the collection of treeNodes in the control. It contains methods Add (adds a treeNode object), Clear (deletes the entire collection) and Remove (deletes a specific node). Removing a parent node deletes all of its children. |
SelectedNode |
The selected node. |
Common Event (Event arguments TreeViewEventArgs) |
|
AfterSelect |
Generated after selected node changes. This is the default event when the control is double clicked in the designer. |
TReeNode properties and methods |
Description |
---|---|
Common Properties |
|
Checked |
Indicates whether the treeNode is checked (CheckBoxes property must be set to true in the parent treeView). |
FirstNode |
Specifies the first node in the Nodes collection (i.e., the first child in the tree). |
FullPath |
Indicates the path of the node, starting at the root of the tree. |
ImageIndex |
Specifies the index of the image shown when the node is deselected. |
LastNode |
Specifies the last node in the Nodes collection (i.e., the last child in the tree). |
NextNode |
Next sibling node. |
Nodes |
Collection of TReeNodes contained in the current node (i.e., all the children of the current node). It contains methods Add (adds a treeNode object), Clear (deletes the entire collection) and Remove (deletes a specific node). Removing a parent node deletes all of its children. |
PrevNode |
Previous sibling node. |
SelectedImageIndex |
Specifies the index of the image to use when the node is selected. |
Text |
Specifies the TReeNode's text. |
Common Methods |
|
Collapse |
Collapses a node. |
Expand |
Expands a node. |
ExpandAll |
Expands all the children of a node. |
GetNodeCount |
Returns the number of child nodes. |
To add nodes to the TReeView visually, click the ellipsis next to the Nodes property in the Properties window. This opens the TreeNode Editor (Fig. 14.27), which displays an empty tree representing the treeView. There are Buttons to create a root, and to add or delete a node. To the right are the properties of current node. Here you can rename the node.
Figure 14.27. TreeNode Editor..
(This item is displayed on page 681 in the print version)
To add nodes programmatically, first create a root node. Create a new TReeNode object and pass it a string to display. Then call method Add to add this new TReeNode to the treeView's Nodes collection. Thus, to add a root node to treeView myTreeView, write
myTreeView.Nodes.Add( new TreeNode( rootLabel ) );
where myTreeView is the TReeView to which we are adding nodes, and rootLabel is the text to display in myTreeView. To add children to a root node, add new TReeNodes to its Nodes collection. We select the appropriate root node from the treeView by writing
myTreeView.Nodes[ myIndex ]
where myIndex is the root node's index in myTreeView's Nodes collection. We add nodes to child nodes through the same process by which we added root nodes to myTreeView. To add a child to the root node at index myIndex, write
myTreeView.Nodes[ myIndex ].Nodes.Add( new TreeNode( ChildLabel ) );
Class treeViewDirectoryStructureForm (Fig. 14.28) uses a treeView to display the contents of a directory chosen by the user. A TextBox and a Button are used to specify the directory. First, enter the full path of the directory you want to display. Then click the Button to set the specified directory as the root node in the treeView. Each subdirectory of this directory becomes a child node. This layout is similar to that used in Windows Explorer. Folders can be expanded or collapsed by clicking the plus or minus boxes that appear to their left.
Figure 14.28. treeView used to display directories.
(This item is displayed on pages 681 - 683 in the print version)
1 // Fig. 14.28: TreeViewDirectoryStructureForm.cs 2 // Using TreeView to display directory structure. 3 using System; 4 using System.Windows.Forms; 5 using System.IO; 6 7 // Form uses TreeView to display directory structure 8 public partial class TreeViewDirectoryStructureForm : Form 9 { 10 string substringDirectory; // store last part of full path name 11 12 // default constructor 13 public TreeViewDirectoryStructureForm() 14 { 15 InitializeComponent(); 16 } // end constructor 17 18 // populate current node with subdirectories 19 public void PopulateTreeView( 20 string directoryValue, TreeNode parentNode ) 21 { 22 // array stores all subdirectories in the directory 23 string[] directoryArray = 24 Directory.GetDirectories( directoryValue ); 25 26 // populate current node with subdirectories 27 try 28 { 29 // check to see if any subdirectories are present 30 if ( directoryArray.Length != 0 ) 31 { 32 // for every subdirectory, create new TreeNode, 33 // add as a child of current node and recursively 34 // populate child nodes with subdirectories 35 foreach ( string directory in directoryArray ) 36 { 37 // obtain last part of path name from the full path name 38 // by finding the last occurence of "" and returning the 39 // part of the path name that comes after this occurence 40 substringDirectory = directory.Substring( 41 directory.LastIndexOf( '\' ) + 1, 42 directory.Length - directory.LastIndexOf( '\' ) - 1 ); 43 44 // create TreeNode for current directory 45 TreeNode myNode = new TreeNode( substringDirectory ); 46 47 // add current directory node to parent node 48 parentNode.Nodes.Add( myNode ); 49 50 // recursively populate every subdirectory 51 PopulateTreeView( directory, myNode ); 52 } // end foreach 53 } // end if 54 } //end try 55 56 // catch exception 57 catch ( UnauthorizedAccessException ) 58 { 59 parentNode.Nodes.Add( "Access denied" ); 60 } // end catch 61 } // end method PopulateTreeView 62 63 // handles enterButton click event 64 private void enterButton_Click( object sender, EventArgs e ) 65 { 66 // clear all nodes 67 directoryTreeView.Nodes.Clear(); 68 69 // check if the directory entered by user exists 70 // if it does then fill in the TreeView, 71 // if not display error MessageBox 72 if ( Directory.Exists( inputTextBox.Text ) ) 73 { 74 // add full path name to directoryTreeView 75 directoryTreeView.Nodes.Add( inputTextBox.Text ); 76 77 // insert subfolders 78 PopulateTreeView( 79 inputTextBox.Text, directoryTreeView.Nodes[ 0 ] ); 80 } 81 // display error MessageBox if directory not found 82 else 83 MessageBox.Show( inputTextBox.Text + " could not be found.", 84 "Directory Not Found", MessageBoxButtons.OK, 85 MessageBoxIcon.Error ); 86 } // end method enterButton_Click 87 } // end class TreeViewDirectoryStructureForm (a) (b) |
When the user clicks the enterButton, all the nodes in directoryTreeView are cleared (line 67). Then the path entered in inputTextBox is used to create the root node. Line 75 adds the directory to directoryTreeView as the root node, and lines 7879 call method PopulateTreeView (lines 1961), which takes a directory (a string) and a parent node. Method PopulateTreeView then creates child nodes corresponding to the subdirectories of the directory it receives as an argument.
Method PopulateTreeView (lines 1961) obtains a list of subdirectories, using method GeTDirectories of class Directory (namespace System.IO) in lines 2324. Method GeTDirectories takes a string (the current directory) and returns an array of strings (the subdirectories). If a directory is not accessible for security reasons, an UnauthorizedAccessException is thrown. Lines 5760 catch this exception and add a node containing "Access Denied" instead of displaying the subdirectories.
If there are accessible subdirectories, lines 4042 use the Substring method to increase readability by shortening the full path name to just the directory name. Next, each string in the directoryArray is used to create a new child node (line 45). We use method Add (line 48) to add each child node to the parent. Then method PopulateTreeView is called recursively on every subdirectory (line 51), which eventually populates the TReeView with the entire directory structure. Note that our recursive algorithm may cause a delay when the program loads large directories. However, once the folder names are added to the appropriate Nodes collection, they can be expanded and collapsed without delay. In the next section, we present an alternate algorithm to solve this problem.