Click here to Skip to main content
Click here to Skip to main content

Drag and Drop Persisting TreeView Control (VB.NET)

By , 29 Nov 2012
 

Introduction

In the previous articles Introduction to TreeView Drag and Drop and Using Serialization to Persist TreeView Control, we looked at persisting and implementing drag and drop functionality to an instance of the TreeView control. In this article, we will take this a step further by extending the TreeView control to incorporate this functionality, making it available for reuse within your projects.

This article will not cover the topics outlined in the previous articles, it will merely highlight the changes required to implement the functionality into an extended TreeView class. It is therefore recommended that you familiarize yourself with these articles if you want to have a full understanding of the project.

Getting Started

Firstly, we are creating an extended user control that's inherited from the standard TreeView control:

Public Class DragDropPersistingTreeView
    Inherits System.Windows.Forms.TreeView
    
    ...

End Class

Usually when creating a custom user control, we include the line Inherits System.Windows.Forms.UserControl, which provides us with a blank control to work with. Here we are replacing this line with Inherits System.Windows.Forma.TreeView, which allows our new control to automatically include all the functionality of the TreeView control without the need for any additional coding.

Overriding Drag and Drop Methods

In the article Introduction to TreeView Drag and Drop, we had to handle the events fired by the TreeView control that was related to drag and drop activities from within the parent form:

Public Sub TreeView1_ItemDrag(ByVal sender As System.Object, _
    ByVal e As System.Windows.Forms.ItemDragEventArgs) _
    Handles TreeView1.ItemDrag
        
    'Set the drag node and initiate the DragDrop 
    DoDragDrop(e.Item, DragDropEffects.Move)

End Sub

Now that we are extending the TreeView control, we need to handle the drag and drop events within the class, therefore the above method needs to be replaced with:

Protected Overrides Sub OnItemDrag( _
    ByVal e As System.Windows.Forms.ItemDragEventArgs)
    
    'Ensure the base method is called 
    MyBase.OnItemDrag(e)
    
    'Set the drag node and initiate the DragDrop 
    DoDragDrop(e.Item, DragDropEffects.Move)

End Sub

While overriding methods in the inherited classes, it is important to ensure that the overridden method in the base class is called with the relevant parameters. This is to ensure that any delegate watching for the event outside of the class will still receive the event, so we include the line:

MyBase.OnItemDrag(e)

Notice this method is declared as Protected, this means that it is only available to classes that are derived from this class. Therefore you would be unable to access the OnItemDrag method of a TreeView from the form or control you place the control on.

The methods OnDragEnter, OnDragOver, OnDragDrop, and OnDragLeave have also been overridden in this way; full documentation is included in the attached project source code at the top of the page. With these methods overridden, you have extended the standard TreeView control to support basic drag and drop operations.

For additional information related to overriding methods, MSDN is a good starting point.

Persisting TreeView Data

In the article Using Serialization to Persist TreeView Control, we created two serializable structures to represent the TreeView and its TreeNode collection, these structures have been lifted directly from this article and placed within the extended TreeView class. However the methods used to expose the load and save functionality need to be modified slightly:

Public Sub SaveToXml(ByVal path As String)
        
    'Create as serializer and file to save TreeViewData
    Dim ser As New _
        System.Xml.Serialization.XmlSerializer(GetType(TreeViewData))
    Dim file As New System.IO.FileStream(path, IO.FileMode.Create)
    Dim writer As New System.Xml.XmlTextWriter(file, Nothing)
    
    'Generate TreeViewData from TreeView and serialize the file
    ser.Serialize(writer, New TreeViewData(Me))
    
    'Tidy up
    writer.Close()
    file.Close()
    file = Nothing

End Sub
    
    
Public Sub LoadFromXml(ByVal path As String)
    
    'Create as serializer and get the file to deserialize
    Dim ser As New _
        System.Xml.Serialization.XmlSerializer(GetType(TreeViewData))
    Dim file As New System.IO.FileStream(path, IO.FileMode.Open)
    Dim reader As New System.Xml.XmlTextReader(file)

    'Deserialize the file and populate the treeview
    Dim treeData As TreeViewData = _
        CType(ser.Deserialize(reader), TreeViewData)
    treeData.PopulateTree(Me)

    'Tidy up
    reader.Close()
    file.Close()
    file = Nothing
        
End Sub

Again, we are creating an XmlSerializer to do the hard work of storing and retrieving the TreeView data. However rather than persisting the data from a TreeView object passed to the methods as a parameter (as in the original article), here we are persisting the extended TreeView itself by passing it as a parameter in the TreeViewData constructor and PopulateTree method.

Using the Control

The downloads at the top of this page provide a sample project with the DragDropPersistingTreeView control in action as well as a single class file for the control. You can build this class into your own project or use it in the same way as any other user control by dragging it from the toolbox to your form or control designer.

Drag and drop functionality will work straight away, provided you set the AllowDrop property to True. To load and save the contents of the TreeView, add a couple of buttons to your form and handle their Click events:

Private Sub SaveButton_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles SaveButton.Click

    DragDropPersistingTreeView1.SaveToXml( _
        "C:\Temp\DragDropPersistingTreeView1.xml")

End Sub

Private Sub LoadButton_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles LoadButton.Click

    DragDropPersistingTreeView1.LoadFromXml( _
        "C:\Temp\DragDropPersistingTreeView1.xml")

End Sub

Conclusion

I hope this article provides an interesting introduction to extending controls, particularly the TreeView, by building on the functionality developed in previous articles into a single control.

Related Articles

If you found this article interesting, you may be interested in other introductory articles related to the TreeView control:

License

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

About the Author

Tom John
Software Developer (Senior) RedFrog.com Limited
United Kingdom United Kingdom
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralXML Serialization CDATA elementmemberspratticus31 Mar '05 - 9:55 
Hi Tom, I love your code btw, it offered a solution to a problem which I was having no luck with (for 3 months). In anycase, it's pretty darn clever, and such as simple solution too.   Your implementation is great, and it saves out the nodes properly -- but I added a string property called "Content", as a given the content is always going to be text-based, containing snippets of code, or misc. bits of text. I wanted to implement that using the CDATA attribute (FYI: I customized the elements so that the properties show as attributes in a tag rather than individual elements). The CDATA element would be contained in the <Content></Content> element as such: <Content><![CDATA[ asdasdad]]></Content>. I'm having a bit of a problem though: I can't quite figure out how to get that to serialize properly. Admittedly I have very little experience with .NET XML classes and what documentation I have read is a little confusing if not slightly vauge with sparse examples. Any help would be very much appreciated!Smile | :)
 
** UPDATE!! **
 
I've found a work around based on some source from <a href = "http://www.dotnetmonster.com/Uwe/Forum.aspx/dotnet-xml/1631/Serializing-as-CData" rel="nofollow">dotnetmonster.com</a>:
<code>
            <XmlIgnoreAttribute()> _
            Public Property Content() As String
                  Get
                        Return _Content
                  End Get
                  Set(ByVal Value As String)
                        _Content = Value
                  End Set
            End Property
 
            <XmlAnyElementAttribute(Name:="content")> _
            Public Property XmlContent() As Xml.XmlElement
                  Get
                        Dim doc As New Xml.XmlDocument
                        Dim elem As Xml.XmlElement = doc.CreateElement("content")
                        Dim cdata As Xml.XmlCDataSection = doc.CreateCDataSection(Content)
                        elem.AppendChild(cdata)
 
                        Return elem
                  End Get
                  Set(ByVal Value As Xml.XmlElement)
                        Content = Value.InnerText.Replace(vbLf, vbCrLf)
                  End Set
            End Property
</code>
GeneralAwesome!memberTodd Davis27 Feb '05 - 7:41 
Thanks - I was just sitting here struggling with the best way to implement a drag-n-drop capable treeview and persist it - honestly, I was - and happened upon this article. You just saved my already balding head quite a few hairs.
 
-Todd Davis (toddhd@gmail.com)
GeneralRe: Awesome!memberTom John27 Feb '05 - 9:01 
Thanks Todd,
 
It's pretty much the same code as the other article you commented on, I just combined it with my article on Drag and Drop into a self contained extended TreeView control.
 
Cheers
 
Tom
GeneralLabel edit and sortmembercodegalaxy24 Feb '05 - 2:46 
I am using your ideas and have run into a small error. The problem may be on my part but I dont see how.
 
Basically I have the treeview set to be able to edit the labels in the nodes - not a problem it works fine - however after editing a node I noticed the sort does not happen - to get around this in the afterlabeledit event I do something like
 

Private Sub TreeView1_AfterLabelEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.NodeLabelEditEventArgs) Handles TreeView1.AfterLabelEdit
TreeView1.SuspendLayout()
Dim Path As String = "C:\Temp\DragDropPersistingTreeView1.xml"
TreeView1.SaveToXml(Path)
TreeView1.LoadFromXml(Path)
TreeView1.ResumeLayout()
End Sub

 
this causes a loop but I am not sure why - maybe you have an insight into this?
GeneralRe: Label edit and sortmemberTom John2 Mar '05 - 5:07 
The problem is that whenever you do anything to the structure of the treeview, i.e. change the order of the nodes the AfterLabelEdit event will fire, hence your loop. It's not really a problem with the implementation of this solution.
 
Here's a thread on Google i found relating to it:
 
TreeView Sorting After LabelEdit[^]
 
I am not so sure there will be a solution, i have had a play around with adding and removing handlers, but i am not convinced that will work.
 
I would suggest searching about a bit deeper for a solution to the problem outlined in the thread above.
 
Hope this helps
 
Tom

GeneralASP.NETmemberdandrade5 Feb '05 - 8:12 
Can this work for ASP.NET pages?
GeneralRe: ASP.NETmemberTom John11 Feb '05 - 10:01 
No it is based on the Windows Forms TreeView Control.
 
Cheers
Tom
GeneralwqeqwesussAnonymous3 Feb '05 - 15:07 
qweqweqw
GeneralRe: wqeqwesussAnonymous3 Feb '05 - 15:08 
kdsfksjdfkj

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

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 29 Nov 2012
Article Copyright 2005 by Tom John
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid