Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / Visual Basic

World's Easiest Multi-Select TreeView

Rate me:
Please Sign up or sign in to vote.
2.80/5 (6 votes)
24 May 2009CPOL3 min read 45.7K   14   12
A quick and easy way to enable multi-select in a TreeView, and an easy way to iterate selected nodes.

Introduction

You would think it would be simple to allow a user to select more than one item in a TreeView, the same way you can in a ComboBox, and then explore the collection of selected items, but it isn't. Microsoft does not provide an easy way to do so. This article will show you an easy way to implement multi-select, and an easy way to maintain a collection of the nodes that are selected--without deriving a new control and without using recursion.

Background

Microsoft's TreeView control allows you to display a checkbox next to every node. But, the checkboxes are a bit ugly, and they are next to every node, which may not be what you want.

I knew I could use an ImageList and substitute my own more graceful checkbox, but the TreeView control would insist on adding an image to every node. If I placed a blank image in the first position of the ImageList, that left ugly gaps next to nodes that didn't get a checkbox.

Just as bad, all the solutions I found for building a collection of selected nodes involved using recursion. Implemented properly, recursion is very useful. But, it can create a terrible mess.

I wanted more control than these approaches allowed, so I decided to bend the rules a bit and implement a very simple solution. Rather than displaying the ugly checkboxes, I decided to just change the background color of the selected nodes. And rather than use recursion, I figured a second, hidden, TreeView could hold my collection of selected nodes.

Using the code

My approach involves trapping the TreeView AfterSelect event. In fact, that's where all of the work happens. The code is surprisingly simple. It assumes you have two TreeViews, one that is marked Visible=False. Since it's not visible, it can be any size you want, and positioned anywhere you want. Think of it as your hidden Notepad.

VB
Private Sub TreeView1_AfterSelect(ByVal sender As System.Object,
                       _ByVal e As System.Windows.Forms.TreeViewEventArgs)
                       _Handles TreeView1.AfterSelect
    If TreeView1.SelectedNode.Level = 0 Then Exit Sub
    Dim newNode As New TreeNode
    newNode = TreeView1.SelectedNode.Clone
    With TreeView1.SelectedNode
        If .BackColor = Color.White Then
            .BackColor = Color.Yellow
            TreeView2.Nodes.Add(newNode)
        Else
            .BackColor = Color.White
            TreeView2.Nodes.RemoveByKey(.Name)
        End If
        TreeView1.SelectedNode = .Parent
    End With
End Sub

The first line of this subroutine prevents the user from selecting a root node (level 0). You can add to this restriction to handle other levels of the TreeView, if you want. For instance, I use this to block all but the lowest level of my TreeView nodes from being selected, which in my case is level 3. So, my code reads:

VB
If TreeView1.SelectedNode.Level < 3 Then Exit Sub

You can't copy a node from one TreeView to another directly, so I clone the SelectedNode. Then, I decide what to do next. If the SelectedNode has a BackColor of white, I change it to yellow. This makes it appear as if a highlighter had marked it. You can choose any color you want, of course. After I change it to yellow, I add the cloned node (a perfect copy of the SelectedNode) to the second, hidden TreeView. If the SelectedNode already had a BackColor of yellow (meaning that the user had selected it previously but now wants to deselect it), I restore its white BackColor and then remove the cloned node from the second TreeView.

The result is that the second, hidden TreeView always contains a collection of the nodes the user has selected in the first, visible TreeView. Once the user has clicked OK, it's a simple matter to iterate through these chosen nodes:

VB
Private Sub ShowIt(ByVal sender As System.Object, ByVal e As System.EventArgs)
                   _Handles btnOK.Click
    Dim aNode As TreeNode
    Dim msg As String = "Selected nodes:" & vbCrLf
    For Each aNode In TreeView2.Nodes
        msg = msg & aNode.Text & vbCrLf
    Next
    MsgBox(msg)
End Sub

Points of interest

All of this works because each node must have a unique name. Trying to use the Text property makes a mess, because you can't guarantee that two nodes will not have the same text.

The last line of the first subroutine above is interesting. I found it annoying that because the focus remained on the SelectedNode, the change in BackColor wasn't immediately apparent. Since I knew that every SelectedNode would have a parent, I decided to shift focus to the parent node.

Conclusion

There are other solutions to these issues, as I mentioned above, and they illustrate some significant programming approaches and creative ideas. One of those solutions might better fit your needs. But, I hope that you find my simple approach a nice alternative.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
Terpy is a consultant reluctantly based in Olympia, Wash. She'd much rather be back in Maine, where the ocean is on the correct side of the road. She is largely a self-taught programmer who clings jealously to her bad habits. Handbells, anyone?

Comments and Discussions

 
GeneralMy vote of 5 Pin
Global Analyser5-Nov-10 0:42
Global Analyser5-Nov-10 0:42 
nice
GeneralIf statement not working Pin
sgiamber16-Jun-09 3:48
sgiamber16-Jun-09 3:48 
GeneralRe: If statement not working Pin
terpy16-Jun-09 6:09
terpy16-Jun-09 6:09 
Generalif color statement Pin
sgiamber16-Jun-09 3:47
sgiamber16-Jun-09 3:47 
GeneralMy vote of 2 Pin
Nickolais4-Jun-09 12:58
Nickolais4-Jun-09 12:58 
GeneralRe: My vote of 2 Pin
terpy16-Jun-09 6:13
terpy16-Jun-09 6:13 
GeneralWhy not derive instead of background TreeView Pin
Nickolais3-Jun-09 11:30
Nickolais3-Jun-09 11:30 
GeneralRe: Why not derive instead of background TreeView Pin
terpy3-Jun-09 11:40
terpy3-Jun-09 11:40 
GeneralRe: Why not derive instead of background TreeView Pin
Nickolais4-Jun-09 12:51
Nickolais4-Jun-09 12:51 
GeneralRe: Why not derive instead of background TreeView Pin
Marlinspike0024-Oct-12 1:16
Marlinspike0024-Oct-12 1:16 
QuestionWhy hidden Treeview? Pin
Mr.PoorEnglish3-Jun-09 11:27
Mr.PoorEnglish3-Jun-09 11:27 
AnswerRe: Why hidden Treeview? Pin
terpy3-Jun-09 11:37
terpy3-Jun-09 11:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.