How to Create a TreeView File Browser Component in VB.NET

Windows Explorer

Windows Explorer's familiar tree navigation.

This tutorial is part of a series: Part 1 | Part 2

As a developer I am often faced with the task of creating a tree-style file browser for navigating the file system similar to Windows Explorer. VB6 provides the DirList and FileList controls, but VB.NET does not provide a control with similar functionality, let alone a full fledged file browser control. It does however include a very nice TreeView control, and with a bit of code you can leverage this powerful control to navigate your file system similar to Windows Explorer.

The idea is pretty simple:

  • Each TreeNode in the TreeView represents a file or folder in the file system.
  • Each TreeNode knows the full path of the file or folder that it represents.
  • Recursion is not used; nodes are populated on demand. When a directory node is expanded by the user, a TreeView event is triggered which clears and repopulates the directory node.

In the first part of this tutorial I’ll show you how to create a simple re-usable File Browser Tree Component by letting the TreeView control do most of the work. In the second part of this tutorial, I’ll show you how to add several features (icons, context menus, drag/drop, etc.) that will spice up your TreeView File Browser Component and bring it more up to par with Windows Explorer.

Getting Started

  1. Open Visual Studio and create a new project – choose the Windows Forms Control Library template.
  2. Your project should now contain a single class “UserControl1″.
  3. Add a new TreeView control to UserControl1’s design surface. Set the Dock property to Fill.

That’s pretty much all there is to designing the TreeView File Browser Component interface.

Adding Some Code

When the component is initialized, we want the TreeView to initialize its top level root node so the user has a place to start browsing through the file system. To make this happen, we need to handle UserControl1’s Load event and initialize the TreeView by populating it with a TreeNode that represents the global RootPath property. We’ll also need to define this global RootPath property so we can use it, so let’s do that first:

We need a RootPath property. Add this code to the declarations section of your UserControl1 class:

Private mRootPath As String = "C:\Windows"
Property RootPath as String
    Get
        Return mRootPath
    End Get
    Set(value as String)
        mRootPath = value
    End Set
End Property

Since we specified “C:\Windows” for the RootPath, this will be the first node added to the TreeView, and the starting point where the user can begin browsing the file system.

Next we’ll handle UserControl1’s Load event, where we will actually add the root node to the TreeView. Add this code to your UserControl1 class:

Private Sub UserControl1_Load(ByVal sender As System.Object, ByVal e   As System.EventArgs) Handles MyBase.Load
    ' when our component is loaded, we initialize the TreeView by  adding  the root node
    Dim mRootNode as New TreeNode
    mRootNode.Text = RootPath
    mRootNode.Tag = RootPath
    mRootNode.Nodes.Add("*DUMMY*")
    TreeView1.Nodes.Add(mRootNode)
End Sub

This code is pretty simple, we instantiate a new TreeNode object (line 3), then set it’s Text and Tag property to the global RootPath property that we created earlier (lines 4-5), add a dummy TreeNode as a chlid of the root TreeNode so the root TreeNode is initially expandable (line 6), and finally add the node to the TreeView (line 7).

Handling the TreeView’s BeforeExpand and BeforeCollapse events

Now for the meat & potatoes. Most of the magic happens when a user expands or collapses a node. Add this code to the UserControl1 class:

Private Sub TreeView1_BeforeCollapse(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles TreeView1.BeforeCollapse
    ' clear the node that is being collapsed
    e.Node.Nodes.Clear()
    ' add a dummy TreeNode to the node being collapsed so it is expandable
    e.Node.Nodes.Add("*DUMMY*")
End Sub

Private Sub TreeView1_BeforeExpand(ByVal sender As Object, ByVal e  As System.Windows.Forms.TreeViewCancelEventArgs) Handles  TreeView1.BeforeExpand
    ' clear the expanding node so we can re-populate it, or else we end up with duplicate nodes
    e.Node.Nodes.Clear()
    ' get the directory representing this node
    Dim mNodeDirectory As IO.DirectoryInfo
    mNodeDirectory = New IO.DirectoryInfo(e.Node.Tag.ToString)
    ' add each subdirectory from the file system to the expanding node as a child node
    For Each mDirectory As IO.DirectoryInfo In mNodeDirectory.GetDirectories
        ' declare a child TreeNode for the next subdirectory
        Dim mDirectoryNode As New TreeNode
        ' store the full path to this directory in the child TreeNode's Tag property
        mDirectoryNode.Tag = mDirectory.FullName
        ' set the child TreeNodes's display text
        mDirectoryNode.Text = mDirectory.Name
        ' add a dummy TreeNode to this child TreeNode to make it expandable
        mDirectoryNode.Nodes.Add("*DUMMY*")
        ' add this child TreeNode to the expanding TreeNode
        e.Node.Nodes.Add(mDirectoryNode)
    Next
End Sub

This is a tutorial after all and the goal is to learn from it, so you’ll have to figure out what this code does yourself :) The code is well commented so you shouldn’t have a problem.

Finishing Up

Go ahead and check out the result. Press F5 to start debugging and you will be presented with a running demo of your component:

Component Test Container

You did it! Now all you need to do is include this Visual Studio Project as a reference in another project and your TreeView File Browser Component will appear in the Control Toolbox where you may add it to a Form. You also have the option of compiling the component as a .dll file and referencing it that way instead.

Conclusion

In this tutorial you learned how to create a simple reusable TreeView File Browser Component. Be sure to check out Part 2!

Resources

24 Comments

  1. Jerrold I, Bodoff says:

    Hi Perry,

    I am new to VB.NET but have over 30 years Consulting / Analyst programming experience on Mainframes. Since I retired I have been using VBA for my own use (previously used VB to interface PC’s with Mainframes) . I searched for an example of TreeView programming but what I found was very complex as most code used recursion. Your code is great and your comments are very helpful. Using your method you do not have to reprogram the world if you add a directory during processing because you only expand when needed. Again fantastic code.

    I did modify your code slightly.
    1. In the UserControl1_Load procedure I added TreeView1.Nodes(0).Expand() before the End Sub

    2. In TreeView1_BeforeExpand event I changed add a dummy Treenode to the following:
    ‘ if there are directories below this one then make this node expandable (jib)
    If (IO.Directory.GetDirectories(mDirectory.FullName).Count > 0) Then
    ‘ add a dummy TreeNode to the directory node so that it is expandable
    mDirectoryNode.Nodes.Add(“*DUMMY*”)
    End If

    3. Before the TreeView1_BeforeExpand event End Sub I added the following:
    ‘ if no nodes were added then display directory files (jib)
    If (e.Node.Nodes.Count <= 0) Then
    Call DisplayFiles(e.Node.Tag)
    End If

    4. Private Sub DisplayFiles(ByVal DirectoryPath As String)
    Dim DirFileName as string
    If (DirectoryPath = "") Then Return

    At this point I needed a ListBox but it could be any list control or array or possibly added to the TreeView node
    With Listbox1
    .Items.Clear()
    For Each DirectoryFile As String In IO.Directory.GetFiles(DirectoryPath)
    DirFileName = Path.GetFileNameWithoutExtension(DirectoryFile)
    .Items.Add(DirFileName)
    Next
    End With

    The DisplayFiles routine was also invoked from the TreeView1_NodeMouseClick event.

    I hope you do not mind my making these changes / comments. It does seem to make the Treeview control behave more like IE.

    As an aside. I found it interesting that you are starting guitar music. I always liked Spanish guitar music and after I retired I took 3 years of Classical Guitar lessons (with music, no tablature which drives me nuts). Unfortuantely I haven't played for a couple of years due to personal circumstances. My guitar has no electronics at all so people just have to be quiet. I am just starting over again from the beginning by myself as lessons for Classical Guitar have gotten so expensive. Besides there are very few Classical Guitar teachers.

    Again, thank you for publishing a fantastic bit of code (using debug I did find out what it is doing except I am not sure of the reasoning for *DUMMY*, except that it is needed.

    Jerrold I. Bodoff

    • Hi Jerrold, thanks for the super long reply! That’s quite some experience you have with mainframes; can’t say that I have ever worked with one myself. I’m surprised that you found this article since this blog is pretty new and I haven’t really done any promoting yet…I guess the search engines are working their magic.

      I’m also glad you found my code useful and your modifications look great. I believe what you are doing is: (1) expand the root node during initialization, (2) you only add a dummy sub-node if the node has contents according to the filesystem, and (3) is triggered when a node is expanded that doesn’t have any sub-nodes in the TreeView, and executes (4) which displays the files for that node in a listbox.

      Because we are populating nodes dynamically instead of recursively, a newly added node in the TreeView does not know about its children until we “request” them by expanding the node and in effect triggering the TreeView1_BeforeExpand event which removes the *DUMMY* node then adds the real children by reading the filesystem. Without this *DUMMY* node, none of the nodes would be expandable, and the TreeView1_BeforeExpand event would never get triggered. I’m sure there are other ways to go about this, but this was the most obvious to me.

      In the future I hope to expand this tutorial into a series to cover some more advanced topics like file rename/move/delete/dragdrop, using real folder and file icons from the Windows shell, etc.

      By the way, Paco De Lucia the flemenco guitarist is a great inspiration to my technical music aspirations (see him play in this video). Some say he’s the best guitarist in the world, but I wouldn’t say that about anyone in particular, maybe only for a specific genre. You might check out some guitar books or video lessons on YouTube, although it might not be the most formal way to master a craft it’s usually how I learn. I picked up an electric guitar with much debate over electric or acoustic because I love how they both sound, and I learned a few beginner tunes and recorded some of my own through Guitar Rig 2, but haven’t progressed much beyond that. It’s hard to find time for everything that I’m passionate about, let alone half of it :)

      Thanks again for the comments and good luck with your guitar and programming.

      Note: I would like to move your comment to the TreeView article so other visitors can benefit from your example code, but I’m not sure if I can move comments in WordPress 3.0 yet…

      Edit: I found that moving your comment (and mine) directly in the database using phpMyAdmin worked like a charm and was pretty simple. I think I’ll write a post about it since I’m sure other users of WordPress 3.0 are wondering how to accomplish this.

    • Jerrold I.Bodoff says:

      Hi Perry,

      You are correct in the analysis of what I am doing. It may be a little slower checking a node for children each time but even on my slow PC it is not noticeable. If one uses recursion to populate the tree it is faster since we already know the children, but what a pile of code to accomplish the function. Besides, as previously mentioned, if a directory is added, you have to re-populate the world. Without recursion it is as simple as an IF statement. Free free to use the modifications as you see fit. Like you, I don’t mind helping others when I can.

      Paco Lucia is primarily flamenco. Paco Pena, Julian Bream and John Williams are the artists I prefer. There are two great Classical sites that you may or may not be aware of:

      http://www.classicalguitarschool.net/en/Default.aspx (This is in Iceland of all places)
      http://www.classicalguitarmidi.com/index.html (This is in France)

      Jerry Bodoff

    • I’m not really educated on the differences between flamenco and spanish; they sound very similar to me. I checked out Paco Pena – Tientos De La Bahia on YouTube which was a good listen, it reminded me a lot of Paco Lucia’s playing.

  2. Awesome tutorial… and it was exactly what I needed. This tutorial opened up an area of this application that I have not ventured off into before but will again soon.. Do have a question… When completed, I did save it, then in another project made a reference to it.. But I did not see it in the control toolbox.. Obviously, I did something incorrectly.. but what?

    Thanks…

  3. Mike, you have a few different options for using this component in other solutions.

    The method that I usually prefer is to add the entire TreeView Component project into my solution (File -> Add Existing Project), then using the Add Reference dialog (Project -> Add Reference), switch to the Projects tab and choose your TreeView Component. This will not only allow you to utilize the TreeView Component in your solution immediately via the ToolBox, but you’ll also be able to modify the TreeView Component code directly since it is now in your solution as a full project. When you compile your solution, the TreeView Component will compile first (ideally – if not you can change this behavior), then the rest of your solution compiles, so you are seeing the most recent version of your TreeView Component every time.

    There are other ways to get your component into a project and this topic can get pretty in depth. In fact, it would make a great addition to this tutorial series and I’m thinking about including it in Part 2 or Part 3.

    You’ll definitely want to know how to comment your properties and make them appear in the property editor like other controls. For example, you can put this code before a property in your component to make it appear in the Visual Studio property editor with a description:

    <Browsable(True), Category("MyCategory"), Description("My Description.")> _
    

    You’d also benefit from using XML comments for your methods. An XML comment can be created by typing three single quotes (”’), and looks like this:

    ''' <summary>
    ''' Add adds two integer numbers.
    ''' </summary>
    ''' <param name="A">The A param is the first number to add.</param>
    ''' <param name="B">The B param is the second number to add.</param>
    ''' <returns>Returns the sum of params A and B.</returns>
    ''' <remarks></remarks>
    Function Add(ByVal A As Integer, ByVal B As Integer) As Integer
        Return A + B
    End Function
    

    When you call this Add method, Visual Studio’s intellisense picks up the XML comments and displays the info as you type out the method call.

  4. Hi Perry,

    I’m new to vb2010 and last used VB6 to program with many years ago. In my new job I have a vb 2010 application that uses 4 treeviews as a means to navigate the file system of a server to 4 different working folders. I have an option in the program for the user to save their current
    working directories to a text file. What I want to be able to do is on program load read the working directories paths from the saved settings file and have the treeviews open up to those saved working directories. How or what I need to do to get the treeview to open at the C:\ root level and then expand the specific directories using the saved paths. Right now the treeviews have a setting to start at the C:\ root level.

    Thanks,

  5. Sanford, I assume you are using the TreeView File Browser Component as discussed in this tutorial. What you should probably do is implement a new method in the TreeView File Browser Component that will accept a file path as an argument. The method will navigate the TreeView just as a user would, except we will automate this in code using recursion.

    For example:

    
        Sub OpenNode(ByVal argFullPath As String)
            OpenNodeRecurse(argFullPath.ToLower, IO.Path.GetPathRoot(argFullPath).ToLower, TreeView1.Nodes)
        End Sub
    
        Sub OpenNodeRecurse(ByVal argFullPath As String, ByVal argRelPath As String, ByVal argNodes As TreeNodeCollection)
            Static mPathPartIndex As Integer
            Static mPathParts() As String = argFullPath.Split("\")
            ' get the current node and expand it
            Dim mNode As TreeNode
            mNode = argNodes(argRelPath)
            mNode.Expand()
            ' if we have reached the full working directory path, we are done and don't need to continue recursion
            If argRelPath = argFullPath Then Exit Sub
            ' increment the current path part index by 1
            mPathPartIndex += 1
            ' append the current path part according to the current path part index
            If argRelPath.EndsWith("\") = True Then
                argRelPath &= mPathParts(mPathPartIndex)
            Else
                argRelPath &= "\" & mPathParts(mPathPartIndex)
            End If
            ' call the method recursively for the next sub-directory
            OpenNodeRecurse(argFullPath, argRelPath, mNode.Nodes)
        End Sub
    

    Look at line 10. The TreeView will find a node (if one exists!) that matches the key we supplied (argRelPath) to the TreeViewCollection by searching each TreeNode’s Name property. We never used the Name property in this tutorial, so you’ll need to add a few lines of code to assign the Name property to all of the TreeNodes:

    Add this to the UserControl1_Load event:

    mRootNode.Name = RootPath.ToLower
    

    Also add this to the TreeView1_BeforeExpand event:

    mDirectoryNode.Name = mDirectory.FullName.ToLower
    

    You’ll notice that I’ve used ToLower everywhere, this is to keep string manipulations as simple as possible. This example also assumes that you have set the RootPath property to “C:\”.

    • With this modification to you program I keep getting the follow error.
      Object reference not set to an instance of an object.
      Static mPathPartIndex As Integer
      Static mPathParts() As String = argRelPath.Split(“\”)
      ‘ get the current node and expand it
      Dim mNode As TreeNode
      mNode = argNodes(argRelPath)
      mNode.Expand() <<<<<<<<<<<<<<
      ' if we have reached the full working directory path, we are done and don't need to continue recursion
      If argRelPath = argFullPath Then Exit Sub
      ' increment the current path part index by 1.
      mPathPartIndex += 1
      ' append the current path part according to the current path part index
      If argRelPath.EndsWith("\") = True Then
      argRelPath &= mPathParts(mPathPartIndex)
      Else
      argRelPath &= "\" & mPathParts(mPathPartIndex)
      End If
      ' call the method recursively for the next sub-directory
      OpenNodeRecurse(argFullPath, argRelPath, mNode.Nodes)

      Can you help thanks gary

  6. hello.

    Your tree view browser was a very good one. But he problem is we cant open a file using that. Can you please posta code.

  7. hemanth,

    You can open a file by using Process.Start(path). All you need to do is handle the TreeView_NodeMouseDoubleClick event. Remember that we store the actual file system path for each file a node represents in the node’s Tag property, so you would do Process.Start(e.Node.Tag).

  8. realy thank you alot for you help and support ,
    am doing project that can allow the user to save and opn documents such as word,pdf ,jpg,mp3 and vedio so as soon as the user selected and pressed the file from the node should open in it defult browser example if he open the word document should open in office word browser directly if he\she open media file should open in windows media player file and so on and give him option for adding new node delete if he made any kind of modificatio on the file the effects should be saved when he pressed save botton on the defult browser ..wish u understand my prolem and give me you help hands
    thank you for your concern and help in advance
    ..

    • Hello abdosh,

      Please see my previous comment, where I mention the use of Process.Start in the TreeView_NodeMouseDoubleClick event. This will allow you to open the file in it’s default (associated) program by double clicking on a node.

      Adding or removing nodes directly in the TreeView is a little more advanced and I hope to explain that in Part 3 of this tutorial series. However, I can tell you that it actually involves creating or deleting the file on the file system and then refreshing TreeView or TreeNode.

  9. thank you perry for you concern i actualy doing graduation prject it is library system it shows the hirachy of tree each node should consist of files wethar documents or vedio i build the tree and bottons but the difficalty which i found is how to load the data from my computer into the selected node and should be saved in data base also the manipulation of the node i have created context menue stripe it appeared on the tree when i right cklick on it but i could’n activate it please help me coz i have to submet it soon..
    thank you bro..
    with my regards ..

  10. abdosh, please see Part 2 of this tutorial series, where I show you how to load files into the TreeView using native system icons, and double click to open them!

  11. Thanks for this.
    I had already created a file system treeview which populated all the sub-directories of the expanded node with the actual files and directories within the sub-directory. This method was very slow with a lot of flickering. After using the dummy node, its working perfectly. Thanks

  12. Hi Perry,

    Thanks for posting this i found it very useful as I am a beginner with VB. I found Jerrold’s post extremely useful as well. I modified the code slightly also to add each sub folder file as a node to allow everything to be seen in one viewing pane.

    Thanks again,

    Chris

  13. Michael Lynn says:

    Thanks for the post… and for the folks that might be coming here looking for similar content. I’ve written an article which shows how to utilize an ExtJS treeview control to create a document browser. The article comes complete with downloadable examples. Here is the Article and here is the example. Enjoy!

    • Thanks for sharing this Michael. I too have built something similar, a shell file browser using ASP.NET and pure Javascript, which saw it’s way into another project of mine called Nest. It’s a very cool project, but I’ve put it on hold, as I am now busy launching a side business in web development/design.

  14. Eric Ainsworth says:

    This worked beautifully. I wanted the the treeview to list all the drives in the system instead of just C:\ so I changed the UserControl1_Load to:

    For Each drv As DriveInfo In My.Computer.FileSystem.Drives
    tv1.Nodes.Add(drv.Name)
    tv1.Nodes(tv1.Nodes.Count - 1).Tag = drv.Name
    tv1.Nodes(tv1.Nodes.Count - 1).Nodes.Add("*DUMMY*")
    Next

    • Nice clean mod! I hope to include something like this in Part 3 of the tutorial series, once I get around to writing it…

  15. batzandvampires says:

    This is an amazing piece of tutorial/Info… Helped me a lot with my project. Thanks a lot..

  16. Perry,

    I hve an error straight off the bat, that the template you start with doesn’t exist in Visual Express 2010, but no matter.

    This code is all good for me once I get it into my forms class, but it keeps telling me I can’t use the handles in the treeview before collapse and expand with this error:

    Handles TreeView1.BeforeCollapse

    Error 1 Handles clause requires a WithEvents variable defined in the containing type or one of its base types. C:\Users\Brett\Documents\Brett\Programming Projects\Bretts Library\CAD Library\CAD Library\frmMain.vb 26 131 CAD Library

    Any help on this?

    Thanks for the great, informative website,

    Brett

  17. I’ll immediately seize your rss as I can’t to find your e-mail subscription hyperlink or e-newsletter service.
    Do you’ve any? Kindly permit me recognise in order that I may just subscribe. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>