(Print this page)

The Treeview control - Part 2
Published date: Saturday, July 1, 2006
On: Moer and Éric Moreau's web site

It seems that the column I wrote for the April 2006 edition of the Level Extreme .Net magazine has generated a lot of enthusiasm. Is there anything else to say about this control? For sure and even after this one you will find plenty of subjects not being fully covered.

This month, I will first convert the last demo to Visual Basic 2005 telling you what’s new about this control. Then I will show you how to use the drag-and-drop feature between 2 of Treeview controls.

Converting to VB2005

Instead of starting from scratch, I wanted to continue to build on top of the previous demo to get a more complete sample instead of having 2 different demos. Be warned that I will not re-explain the loading, the images, and the checkboxes that were already covered in the previous article.

I had 2 choices here:

  • I could open the previous solution created in VB.Net 2003 from the VS2005 IDE.
  • I could create a brand new project and copy-paste previous objects from the old demo.

I decided to go using the second method because it is a so small project and I like to have the .designer.vb file instead of the “Windows Form Designer generated code” section.

What’s new?

I would answer this short answer: sadly, not many but small things that may help you getting extra cool features.

The first thing you see when you compare the list of properties is that a new property called LineColor is added. Can you guess what you will use it for? You can now pick any color instead of the plain old black.

Another thing you can see is that the Sorted property has gone! But don’t panic. It is still there, ready to use and working as expected. It simply does not appear in IntelliSense. More on this later in this article.

Some new events have been added. At least 3 will be useful when you work with TreeNode: NodeMouseClick, NodeMouseDoubleClick and NodeMouseHover. Don’t forget that not all users are always using the mouse and that those events are dedicated for mouse events.

There is also a new DrawMode property that let you completely customize the appearance of the Treeview control. To do this, set the DrawMode property to a value other than TreeViewDrawMode.Normal and handle the DrawNode event. The help file has an example of that.

Figure 1: The Demo application

Sorting Treeview contents

As I told you in the previous section, the Sorted property has disappeared from the Property window and also from the IntelliSense.

In addition to the Boolean Sorted property, you can now use the TreeViewNodeSorter property. This property can be set to any class implementing the IComparer interface. That means that you can now sort easily the content of your Treeview the way you always dreamed about. This is an example (coming straight from the help file) of such a class that sorts the Treeview content according to the length of the string from the shortest to the longest.

' Create a node sorter that implements the IComparer interface.
Private Class NodeSorter
    Implements IComparer

    ' Compare the length of the strings, or the strings
    ' themselves, if they are the same length.
    Public Function Compare(ByVal x As Object, ByVal y As Object) _
        As Integer Implements IComparer.Compare
        Dim tx As TreeNode = CType(x, TreeNode)
        Dim ty As TreeNode = CType(y, TreeNode)

        If tx.Text.Length <> ty.Text.Length Then
            Return tx.Text.Length - ty.Text.Length
        End If
        Return String.Compare(ty.Text, tx.Text)
    End Function
End Class

When you are ready to sort your Treeview, simply set the property like this:

TreeView1.TreeViewNodeSorter = New NodeSorter()

There is one small gotcha you need to be aware of. If you set the TreeViewNodeSorter property to a class like we just did, it doesn’t seem to be possible to revert back to the plain old Sorted property at first even if the help file clearly states: “After the TreeViewNodeSorter is set, if the Sorted property is set to true, the nodes will be sorted in alphabetical order”.

The official “undocumented” workaround is to ensure that the Sorted property is set to false and the TreeviewNodeSorter property is set to Nothing before trying to set the Sorted property to True again like this:

'This will sort the string in alphabetical order
With TreeView1
    .BeginUpdate()
    If .TreeViewNodeSorter IsNot Nothing Then
        .Sorted = False
        .TreeViewNodeSorter = Nothing
    End If
    .Sorted = True
    .EndUpdate()
End With

Drag and Drop

Implementing this feature is not as simple as setting a couple of properties, you need to write code. Don’t complain, that’s why you are (probably) paid for after all! Do you remember a long time ago (February 2004 edition of the UTMag), I wrote an article on Drag and Drop? Treeviews were not covered by the article but some events are explained there. Have a look at it if you are not too familiar with the concepts.

In order to demonstrate this feature, I have added another Treeview control to my form (named Treeview2). I have also modified the loading of the Treeview to add the Categories (and not the Products) to the Treeview2.

The very first thing you need to do in order to support the drop feature is to set the AllowDrop property of the control(s) that will receive data to True (the default is False).

You then need to handle a minimum of 3 events to fully implement the basic feature. If you download the demo I made available to you, you will find that all these 3 events are handling the events of both Treeview controls at the same time (check the Handles clause on the events declarations).

The first event to handle is called ItemDrag. This event is raised from the source Treeview control as soon as the user starts to drag a tree node. What you need to do here is to call the DoDragDrop method to initiate the drag and drop operation. While initiating the operation, you also determine if the operation will be a move or a copy operation (here the copy operation is done by using the right button of the mouse). Also notice that the current node (e.item) is kept in memory to be retrieved later. The code you need is as simple as this:

If e.Button = Windows.Forms.MouseButtons.Left Then
    ' Move the dragged node when the left mouse button is used.
    DoDragDrop(e.Item, DragDropEffects.Move)
ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
    ' Copy the dragged node when the right mouse button is used.
    DoDragDrop(e.Item, DragDropEffects.Copy)
End If

The second event to handle is the DragEnter event and requires even less code then the previous one. This event must be handled on each control that may be the destination. It is mainly used to change the mouse icon to inform users where the drop can be done. This is the single line of code you need:

e.Effect = e.AllowedEffect 

The last event you need to write code for, and it won’t be a single line this time, is the DragDrop event. This event occurs when a Node is dropped on the Treeview. Here is what you need to do:

  • Validate that the item dropped is of the right kind (GetDataPresent).
  • Find the Node to which the new node will be added as a child (GetNodeAt).
  • Retrieve the node that was placed in memory in the ItemDrag event (GetData).
  • Add this node to the destination Treeview (Nodes.Add).
  • If the operation is a move, you need to delete the original node (newNode.Remove).

This is the code you need:

Dim newNode As TreeNode
If e.Data.GetDataPresent("System.Windows.Forms.TreeNode", False) Then
    Dim pt As Point
    Dim destinationNode As TreeNode
    pt = CType(sender, TreeView).PointToClient(New Point(e.X, e.Y))
    destinationNode = CType(sender, TreeView).GetNodeAt(pt)
    newNode = CType(e.Data.GetData("System.Windows.Forms.TreeNode"), TreeNode)
    If Not destinationNode.Equals(newNode) Then
        destinationNode.Nodes.Add(CType(newNode.Clone, TreeNode))
        destinationNode.Expand()
        If e.Effect = DragDropEffects.Move Then
            newNode.Remove()
        End If
    End If
End If

Conclusion

As per your request, I have revisited a previous article. I will do that for many topics I have covered over the last few years to inform you about the new features brought to you buy Visual Studio 2005 while trying to get deeper.

I hope you appreciated the topic and see you next month.


(Print this page)