Article source code: custom_treeview.zip
With VB.NET you can synchronize internal objects with your user interface by using inheritance. This simplifies the amount of code you must write to know what the user selected and to deal with it appropriately. In the past, you may have concatenated text together for display then parsed it apart to access a unique value after the user selected an item; or you may have used an array or collection with the same number of items so you could use the selected index to know which item was chosen. Now you can simplify your code by extending the built-in functionality of Windows Forms controls and use the much-touted inheritance new to VB.NET.

This article demonstrates how to build a treeview where the nodes are based on different objects. A simple example is a folder and file hierarchy where each object needs different properties. A more complex example is an object model with a class at one level and with methods, properties, events, etc., at a level below that. In this example, Category is at the top level and AccountType and PartType are the second-tier nodes. Each class will contain a property that is not part of the other classes. In the real world each of these classes might be very different from each other.
Create Your Object Model
The first step is to create a VB.NET Windows Application project named "CustomTreeView". Rename the default Form1.vb
to CustomTreeViewForm.vb
. Change the text property of the form to "Custom TreeView". Add a treeview called tvwCategories
and a textbox called txtSelectedID
to the form.
Go to the code pane for the form. Rename the default class from "Public Class Form1" to "Public Class CustomTreeViewForm". Below the "End Class" create a class called AccountType
. Add one property for DisplayName
and one property for AccountTypeID
. You can do this by declaring a variable or by using a property procedure. To do the former, type "Public AccountType as String".
Public Class AccountType
Public AccountTypeID As String
Public DisplayName As String
End Class
|
To create the other classes, copy and paste the entire AccountType
class below the "End Class". Select the copy and do a search and replace of the word "AccountType" and change it to "PartType". Make another copy of AccountType
and this time change "AccountType" to "Category".
Public Class PartType
Public PartTypeID As String
Public DisplayName As String
End Class
Public Class Category
Public CategoryID As String
Public DisplayName As String
End Class
|
To group multiple items of each class together, you can create classes that inherit from one the collection types of .NET. Do this by creating a new class called "Categories" and typing "Inherits CollectionBase" on the line after the declaration. The minimum code needed to make the collection useful is an Add
function receiving the Category
type and returning the item after it has been added the InnerList
collection, which is part of the CollectionBase
you declared. Create collection classes for AccountTypes
and PartTypes
in a similar manner. You will not do this for your custom treenodes you create later because they will be grouped in the treeview when they are added to it.
Public Class Categories
Inherits CollectionBase
Public Function Add(ByVal Value As Category) As Category
Me.InnerList.Add(Value)
Add = Value
End Function
End Class
|
To make the two-tier relationship between the Category
class and the AccountTypes
and PartTypes
classes create variables to reference collections of those types by modifying the Category
class.
Public Class Category
Public CategoryID As String
Public DisplayName As String
Public AccountTypes As New AccountTypes()
Public PartTypes As New PartTypes()
End Class
|
Creating Custom TreeNodes
Add a new class called "AccountTypeTreeNode". Just below the class declaration type "Inherits TreeNode". This indicates the class will have all the other properties of a treenode along with any custom properties that you add. Next, declare a new property called AccountType. To set this variable write your own "New" procedure and pass the AccountType you want to associate with the node as an argument. Tell the treenode which property you want the user to see by typing "Me.Text = AccountType.DisplayName"
Public Class AccountTypeTreeNode
Inherits TreeNode
Public AccountType As AccountType
Sub New(ByVal Value As AccountType)
MyBase.New()
AccountType = Value
Me.Text = AccountType.DisplayName
End Sub
End Class
|
Use the same methods to create classes for PartTypeTreeNode
and CategoryTypeTreeNode
.
Now create a routine within the CustomTreeViewForm class to fill the treeview. Call this function after the call to "InitializeComponent()" in the form's collapsed "Windows Form Designer generated code" section. The code below will fill the items for your collections and then create the customized nodes in the treeview.
Dim objCategories As New Categories()
Dim i As Integer
Dim x As Integer
For i = 1 To 5
With objCategories.Add(New Category())
.CategoryID = "CAT" & i
.DisplayName = "Category " & i
For x = 1 To 3
With .AccountTypes.Add(New AccountType())
.AccountTypeID = "A" & x
.DisplayName = "AccountType " & x
End With
With .PartTypes.Add(New PartType())
.PartTypeID = "P" & x
.DisplayName = "PartType " & x
End With
Next x
End With
Next i
With Me.tvwCategories
Dim objCategory As Category
Dim objAccountType As AccountType
Dim objPartType As PartType
Dim objCategoryTreeNode As CategoryTreeNode
For Each objCategory In objCategories
objCategoryTreeNode = New CategoryTreeNode(objCategory)
.Nodes.Add(objCategoryTreeNode)
With objCategoryTreeNode
For Each objAccountType In objCategory.AccountTypes
.Nodes.Add(New AccountTypeTreeNode(objAccountType))
Next
For Each objPartType In objCategory.PartTypes
.Nodes.Add(New PartTypeTreeNode(objPartType))
Next
End With
Next
End With
|
The last thing to do is to interpret the selected node and do something with that value. Click on the Class Name dropdown above your code pane and select tvwCategories
. The Method Name dropdown will be filled with events you can handle. Click on the AfterSelect
item. An empty routine will be inserted for you. This event will fire after the user has changed the selected node in the treeview. tvwCategories.SelectedNode.GetType.ToString
will return a text value such as "CustomTreeView.AccountTypeTreeNode" where "CustomTreeView" is the name of your project. This is how you tell which type of treenode was selected. For each type of node, declare a variable and cast (or convert) the more generic treenode to the specific type of treenode so its properties can be accessed. Finally, set the text property of the textbox to display an internal property of the item selected.
Private Sub tvwCategories_AfterSelect(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles _
tvwCategories.AfterSelect
Dim objNode As TreeNode
objNode = tvwCategories.SelectedNode
Select Case objNode.GetType.ToString
Case "CustomTreeView.CategoryTreeNode"
Dim objCategoryTreeNode As CategoryTreeNode
objCategoryTreeNode = CType(objNode, CategoryTreeNode)
txtSelectedID.Text = _
objCategoryTreeNode.Category.CategoryID.ToString
Case "CustomTreeView.AccountTypeTreeNode"
Dim objAccountTypeTreeNode As AccountTypeTreeNode
objAccountTypeTreeNode = CType(objNode, AccountTypeTreeNode)
txtSelectedID.Text = _
objAccountTypeTreeNode.AccountType.AccountTypeID.ToString
Case "CustomTreeView.PartTypeTreeNode"
Dim objPartTypeTreeNode As PartTypeTreeNode
objPartTypeTreeNode = CType(objNode, PartTypeTreeNode)
txtSelectedID.Text = _
objPartTypeTreeNode.PartType.PartTypeID.ToString
End Select
End Sub
|
Run the project and click on items at different levels of the treeview. The textbox will show the internal property.
Summary
Inheritance allows you to derive from an existing object and to add your own properties, etc. A practical use for this is to keep track of items in the UI without complex synching of different objects and without having to do messy lookups once an item has been selected.
Related devCity.NET articles: