none
How do I Show Child Nodes of Treeview

    Question

  • I have the following code for a treeview, It only shows a +sign against some folders, mostly system folders but not others, can anybody suggest a mod to this code to show all childs, irrespective of how many levels the child folders exist?

    any help much appreciated

     

    Dim basenode As System.Windows.Forms.TreeNode
            If IO.Directory.Exists(path) Then
                If path.Length <= 3 Then
                    basenode = ThisTreeview.Nodes.Add(path)
                Else
                    basenode = ThisTreeview.Nodes.Add(My.Computer.FileSystem.GetName(path))
                End If
                basenode.Tag = path
                Treeview_LoadDir(path, basenode)
            Else
                Throw New System.IO.DirectoryNotFoundException()
            End If

            ThisTreeview.Sort()
            ThisTreeview.TopNode.Expand()

      

        Public Sub Treeview_LoadDir(ByVal DirPath As String, ByVal Node As Windows.Forms.TreeNode)

            On Error Resume Next
            Dim Dir As String
            Dim Index As Integer
            If Node.Nodes.Count = 0 Then
                For Each Dir In My.Computer.FileSystem.GetDirectories(DirPath)
                    Index = Dir.LastIndexOf("\")
                    Node.Nodes.Add(Dir.Substring(Index + 1, Dir.Length - Index - 1))
                    Node.LastNode.Tag = Dir
                    Node.LastNode.ImageIndex = 0
                Next
            End If

    Thursday, September 29, 2011 6:22 AM

Answers

  • Thanks for providing the code.

    My understanding now is that you want to fill sub nodes when opening the parent node. Is this correct?

     

    Instead of modifying your code, I'm posting my own version. Let me please know if it's appropriate for you. Try the following code in a new project. Add two controls on the form: A listbox called "lstDrives" and a Treeview called "ctlTreeview". Use this code:

    Public Class Form1
    
       Private Class DirectoryNode
          Inherits TreeNode
    
          Public ReadOnly Directory As IO.DirectoryInfo
    
          Public Sub New(ByVal Directory As IO.DirectoryInfo)
    
             MyBase.New(GetDisplayName(Directory))
    
             Me.Directory = Directory
    
          End Sub
          Private Shared Function GetDisplayName(ByVal directory As IO.DirectoryInfo) As String
    
             Dim result As String
    
             result = IO.Path.GetFileName(directory.Name)
    
             If result.Length = 0 Then
                Return directory.FullName
             Else
                Return result
             End If
    
          End Function
       End Class
    
       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
          For Each drive In IO.DriveInfo.GetDrives
             ctlDrives.Items.Add(drive.Name)
          Next
    
       End Sub
    
       Private Sub ctlDrives_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctlDrives.SelectedIndexChanged
    
          Dim node As DirectoryNode
    
          ctlTreeview.Nodes.Clear()
    
          node = New DirectoryNode(New IO.DirectoryInfo(ctlDrives.Text))
          FillNode(node)
          ctlTreeview.Nodes.Add(node)
    
       End Sub
       Private Sub FillNode(ByVal node As DirectoryNode)
    
          Dim dirs As IO.DirectoryInfo()
    
          Try
             dirs = node.Directory.GetDirectories
          Catch ex As Exception   'unauthorized access or other reasons
             Return
          End Try
    
          For Each Dir As IO.DirectoryInfo In dirs
             node.Nodes.Add(New DirectoryNode(Dir))
          Next
    
       End Sub
       Private Sub ctlTreeview_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles ctlTreeview.BeforeExpand
    
          ctlTreeview.BeginUpdate()
    
          For Each node As DirectoryNode In e.Node.Nodes
             If node.Nodes.Count = 0 Then
                FillNode(node)
             End If
          Next
    
          ctlTreeview.EndUpdate()
    
       End Sub
    
    End Class
    


     


    Armin
    • Marked as answer by x38class Friday, September 30, 2011 8:50 PM
    Friday, September 30, 2011 11:34 AM

All replies

  • From your code I fail to derive what's your goal.
    Do you want to specify a path, add it as a node in the treeview, then recursively add sub nodes for the sub folders, and so on?
    Could you please illustrate this statement: "It only shows a +sign against some folders, mostly system folders but not others"
    Armin
    Thursday, September 29, 2011 7:00 AM
  • Just realized my problem, the child nodes are there when first populated but when drives are changed or re loaded a second time, that is when they are missing, so how do I reset the nodes to show child nodes every time
    Thursday, September 29, 2011 7:02 AM


  • Just realized my problem, the child nodes are there when first populated but when drives are changed or re loaded a second time, that is when they are missing, so how do I reset the nodes to show child nodes every time
    Thursday, September 29, 2011 7:05 AM
  • That suggests that the TreeView is nort being cleared properly prior to reloading.  If you remove your On Error and put some proper error handling around only the line of code that might actually create the error you are trying to trap, you may be able to see what is happening when the directories get re-loaded.
    Thursday, September 29, 2011 7:10 AM
  • I'm still unsure, I am sorry. Maybe you just want to clear the treeview before refilling it: ThisTreeview.Nodes.Clear


    Armin
    Thursday, September 29, 2011 7:11 AM
  • Done that, does not show + 2nd time around
    Thursday, September 29, 2011 7:13 AM
  • For Acamar, thanks for replying, only there is no error, just that my initial loading of the directory tree is "C:\" which shows all the folders on drive C , it also shows + against the folders that have subdirectories.

    Only problem is if I change drive to D & then back to C, the + are not there.

    Thursday, September 29, 2011 9:38 AM
  • For Acamar, thanks for replying, only there is no error, just that my initial loading of the directory tree is "C:\" which shows all the folders on drive C , it also shows + against the folders that have subdirectories.

    If there is no error, then you can remove the error handling completely, and you can put a breakpoint at the start of the routine.  Then, when the applciation breaks at that pint, you can step through the routine a line at a time, and determine why the routine is apparently not traversing into the subfolders, by examining the variables in that routine(including the treeview and its nodes) at each step in the procedure.

    Thursday, September 29, 2011 10:22 AM
  • There actually is no error handling at all, and no error are reported (just a missing + on 2nd time of loading) only condition that is set is

    if path.length <= 3 then

    Thursday, September 29, 2011 12:02 PM
  • What did your debugging efforts reveal?
    Armin
    Thursday, September 29, 2011 12:52 PM
  • Have spent quite a bit of time trying different code options with no answers, if you have a specific area that you can suggest may help, please advise
    Thursday, September 29, 2011 8:38 PM
  • With the code provided, after inserting treeview.nodes.clear, I can not reproduce the problem you describe. Could you please the whole code you have?
    Armin
    Thursday, September 29, 2011 8:44 PM
  • The first block of code is in a sub routine, so there is no other code except the sub is called like this

     

    Treeview_LoadFolderTree(MyFormTreeview1,"c:\")

    I have got treeview.nodes.clear, did you run it twice with the form loaded only once & changing drives from C to D then back to C using a list box

    Thursday, September 29, 2011 8:56 PM
  • You haven't mentioned "Treeview_LoadFolderTree" before, but I guess the signature is

        Sub Treeview_LoadFolderTree(ByVal ThisTreeview As TreeView, ByVal path As String)

    and the content is the first part of your code.

    I can call it alternating with "c:\" and "d:\" but see no problem.

    You've mentioned a Listbox, so there must be code to use a path depending on the selected item in the Listbox. Can you show this code?

     


    Armin
    Thursday, September 29, 2011 9:10 PM
  • So are you saying that you have now removed

    On Error Resume Next

    What was the result when you inserted your breakpoint and examined the variables in that routine each time it was executed? For instance, were you getting the folder lists that you expected for each folder path that was provided? When the node was created, could you see that it became part of the TreeView?

    Thursday, September 29, 2011 9:59 PM
  • First I have an apology, I failed to include some code, so my apologies for that.

    Here is the full code

    step 1
    call desired drive
    Treeview_LoadFolderTree(me.TreeView1, Mid(lstDrives.Text, 1, 3)), ie "c:\"

    step 2

    in module
     Public Sub Treeview_LoadFolderTree(ByVal ThisTreeview As System.Windows.Forms.TreeView, ByVal path As String)

           
            Treeview_Parent_Folder = path

           
            ThisTreeview.Nodes.Clear()
           
            Dim basenode As New System.Windows.Forms.TreeNode
            If IO.Directory.Exists(path) Then
                If path.Length <= 3 Then
                    basenode = ThisTreeview.Nodes.Add(path)
                Else
                    basenode = ThisTreeview.Nodes.Add(My.Computer.FileSystem.GetName(path))
                End If
                basenode.Tag = path
                Treeview_LoadDir(path, basenode)
            Else
                Throw New System.IO.DirectoryNotFoundException()
            End If

           
            ThisTreeview.Sort()
            ThisTreeview.TopNode.Expand()

        End Sub

    step 3
    in  module

    Public Sub Treeview_LoadDir(ByVal DirPath As String, ByVal Node As Windows.Forms.TreeNode)

            On Error Resume Next
            Dim Dir As String
            Dim Index As Integer
           
            If Node.Nodes.Count = 0 Then
                For Each Dir In My.Computer.FileSystem.GetDirectories(DirPath)
                    Index = Dir.LastIndexOf("\")
                    Node.Nodes.Add(Dir.Substring(Index + 1, Dir.Length - Index - 1))
                    Node.LastNode.Tag = Dir
                    Node.LastNode.ImageIndex = 0
                    Console.WriteLine("Treeview_LoadDir" & " " & Dir)

                Next
            End If

        End Sub

    step 4

    from Main form on Treeview1After expand

    Private Sub TreeView1_AfterExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterExpand

            Treeview_Expand(e)

         
        End Sub

    step 5

    In Module
    Sub Treeview_Expand(ByVal e As System.Windows.Forms.TreeViewEventArgs)

            Dim n As System.Windows.Forms.TreeNode
            For Each n In e.Node.Nodes
                Treeview_LoadDir(n.Tag, n)
                Console.WriteLine("Treeview_Expand" & " " & n.Tag)
            Next

        End Sub

     

    It now appears that the problem is in step 5 where n.tag is null second time around, so somewhere something needs to be reset so the n.tag is valid

    console shows "Treeview_Expand & Directory" 1st time, but only shows "Treeview_Expand" second time around, maybe there is a problem with e.node.nodes?

     

    Friday, September 30, 2011 6:50 AM
  • Thanks for providing the code.

    My understanding now is that you want to fill sub nodes when opening the parent node. Is this correct?

     

    Instead of modifying your code, I'm posting my own version. Let me please know if it's appropriate for you. Try the following code in a new project. Add two controls on the form: A listbox called "lstDrives" and a Treeview called "ctlTreeview". Use this code:

    Public Class Form1
    
       Private Class DirectoryNode
          Inherits TreeNode
    
          Public ReadOnly Directory As IO.DirectoryInfo
    
          Public Sub New(ByVal Directory As IO.DirectoryInfo)
    
             MyBase.New(GetDisplayName(Directory))
    
             Me.Directory = Directory
    
          End Sub
          Private Shared Function GetDisplayName(ByVal directory As IO.DirectoryInfo) As String
    
             Dim result As String
    
             result = IO.Path.GetFileName(directory.Name)
    
             If result.Length = 0 Then
                Return directory.FullName
             Else
                Return result
             End If
    
          End Function
       End Class
    
       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
          For Each drive In IO.DriveInfo.GetDrives
             ctlDrives.Items.Add(drive.Name)
          Next
    
       End Sub
    
       Private Sub ctlDrives_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctlDrives.SelectedIndexChanged
    
          Dim node As DirectoryNode
    
          ctlTreeview.Nodes.Clear()
    
          node = New DirectoryNode(New IO.DirectoryInfo(ctlDrives.Text))
          FillNode(node)
          ctlTreeview.Nodes.Add(node)
    
       End Sub
       Private Sub FillNode(ByVal node As DirectoryNode)
    
          Dim dirs As IO.DirectoryInfo()
    
          Try
             dirs = node.Directory.GetDirectories
          Catch ex As Exception   'unauthorized access or other reasons
             Return
          End Try
    
          For Each Dir As IO.DirectoryInfo In dirs
             node.Nodes.Add(New DirectoryNode(Dir))
          Next
    
       End Sub
       Private Sub ctlTreeview_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles ctlTreeview.BeforeExpand
    
          ctlTreeview.BeginUpdate()
    
          For Each node As DirectoryNode In e.Node.Nodes
             If node.Nodes.Count = 0 Then
                FillNode(node)
             End If
          Next
    
          ctlTreeview.EndUpdate()
    
       End Sub
    
    End Class
    


     


    Armin
    • Marked as answer by x38class Friday, September 30, 2011 8:50 PM
    Friday, September 30, 2011 11:34 AM
  • Excellent !! Thank you

    There seems many variations of code examples for this, as inbetween replying & sleeping I have tried others without success

    Just 2 minor points to make it perfect, your code above shows ctlDrives, your pre-amble shows lstDrives

    add:

          ctlTreeview.sort()
    ctlTreeview.TopNode.Expand()
      to
    ctlDrives_SelectedIndexChanged
     Private Sub ctlDrives_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctlDrives.SelectedIndexChanged

    Dim node As DirectoryNode

    ctlTreeview.Nodes.Clear()

    node = New DirectoryNode(New IO.DirectoryInfo(ctlDrives.Text))
    FillNode(node)
    ctlTreeview.Nodes.Add(node)

    ctlTreeview.sort()
    ctlTreeview.TopNode.Expand()

    sort()



    End Sub
    Friday, September 30, 2011 9:18 PM
  • I'm glad you finally have a solution. Happy coding!
    Armin
    Friday, September 30, 2011 9:26 PM
  • Particularly for Armin, thank you, this might be useful if you sue treeviews on more than one form or many treeviews on one form.

    My purpose in life is to make things simple, I like using a module to have subs/functions to do the work for me when it is likely to be beneficial so I only have one lot of code to contend with.

    As a consequence I have a form with many treeviews where a user can select folders from any one for which I need the resulting folder name, I cannot get the name simply by sending to the treeview this path:"C:\users\myname\My Documents\Pictures"

    Treeview only shows

    Pictures

                 \ abc

                 \ def

                 \ ghi

    User selects Pictures\abc

    All I get is "Pictures\abc"

    Another treeview might show something entirely different, I have solved this problem with the following code.

    It relies on adding treeviews to the form in the name & order windows presents, ie Treeview1, treeview2 etc, if you want to use the code below & use different names then they must conform to a numerical sequence ie MyTreeview1, MyTreeview2, etc & you will need to change the code accordingly

    I would prefer a more simple method but time is running short so I have had to resort to what I know best

    On Form Load or from a list Box of drives, or a parent Folder & Child

     TreeView1.Nodes.Clear()
     Treeview_LoadFolderTree(Mid(lstDrives.Text, 1, 3), TreeView1)

    or
    Treeview_LoadFolderTree("C:\Users\MyDocuments\Pictures", TreeView1)


    or next treeview, etc

    TreeView2.Nodes.Clear()
     Treeview_LoadFolderTree(Mid(lstDrives.Text, 1, 3), TreeView2)

    or
    Treeview_LoadFolderTree("C:\Users\MyDocuments\Pictures", TreeView2)

    In the Treeview events

    Private Sub TreeView1_AfterSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView1.AfterSelect

            dim FolderName as String

            If TreeView1.Enabled = True Then
               FolderName = Treeview_GetFolder(TreeView1)
            End if

    end sub



    Private Sub TreeView2_AfterSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles TreeView2.AfterSelect

            dim FolderName as String

            If TreeView2.Enabled = True Then
               FolderName = Treeview_GetFolder(TreeView2)
            End if

    end sub

    Private Sub TreeView1_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles TreeView1.BeforeExpand

            Treeview_BeginUpdate(TreeView1, e)

        End Sub



    Private Sub TreeView2_BeforeExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs) Handles TreeView2.BeforeExpand

            Treeview_BeginUpdate(TreeView2, e)

        End Sub

     

    In Module

        Public Treeview_Original_path(20) As String

        Public Class DirectoryNode
            Inherits TreeNode

            Public ReadOnly Directory As IO.DirectoryInfo

            Public Sub New(ByVal Directory As IO.DirectoryInfo)

                MyBase.New(GetDisplayName(Directory))

                Me.Directory = Directory

            End Sub
            Private Shared Function GetDisplayName(ByVal directory As IO.DirectoryInfo) As String

                Dim result As String

                result = IO.Path.GetFileName(directory.Name)

                If result.Length = 0 Then
                    Return directory.FullName
                Else
                    Return result
                End If

            End Function
        End Class
        Function Treeview_GetFolder(ByVal ThisTreeview As System.Windows.Forms.TreeView) As String

            Dim ThisTreeview_SelectedNode As String
            Dim Treeview_path As String

            ThisTreeview_SelectedNode = ThisTreeview.SelectedNode.FullPath
            If Len(ThisTreeview_SelectedNode) <> 3 Then
                If Mid(ThisTreeview_SelectedNode, 3, 2) = "\\" Then
                    ThisTreeview_SelectedNode = Mid(ThisTreeview_SelectedNode, 1, 3) & Mid(ThisTreeview_SelectedNode, 5, Len(ThisTreeview_SelectedNode) - 4)
                End If
            End If

            ' Find the path originally given to treeview
            Dim a As Integer
            Dim b As Integer
            For a = 1 To UBound(Treeview_Original_path)
                If UCase(ThisTreeview.Name) = UCase("Treeview" & CStr(a)) Then
                    b = InStrRev(Treeview_Original_path(a), "?")
                    Treeview_path = Mid(Treeview_Original_path(a), b + 1, Len(Treeview_Original_path(a)) - b)
                    Exit For
                End If
            Next

            ' If path was parent & child, ie not a drive("c:\") build correct path
            If Not InStr(1, ThisTreeview_SelectedNode, Treeview_path) Then
               
                Dim DirPosn As Integer
                DirPosn = InStr(ThisTreeview_SelectedNode, "\")
                If DirPosn > 0 Then
                    DirPosn = InStrRev(Treeview_path, Mid(ThisTreeview_SelectedNode, 1, DirPosn - 1))
                    ThisTreeview_SelectedNode = Mid(Treeview_path, 1, DirPosn - 1) & ThisTreeview_SelectedNode
                Else
                    ThisTreeview_SelectedNode = Treeview_path
                End If

            End If

            ThisTreeview.Enabled = False
            ThisTreeview.SelectedNode = Nothing
            ThisTreeview.Enabled = True

            Return ThisTreeview_SelectedNode

        End Function
        Public Sub Treeview_FillNode(ByVal node As DirectoryNode)

            Dim dirs As IO.DirectoryInfo()

            Try
                dirs = node.Directory.GetDirectories
            Catch ex As Exception   'unauthorized access or other reasons
                Return
            End Try

            For Each Dir As IO.DirectoryInfo In dirs
                node.Nodes.Add(New DirectoryNode(Dir))
            Next

        End Sub
        Sub Treeview_BeginUpdate(ByVal Thistreeview As TreeView, ByVal e As System.Windows.Forms.TreeViewCancelEventArgs)

            Thistreeview.BeginUpdate()

            For Each node As DirectoryNode In e.Node.Nodes
                If node.Nodes.Count = 0 Then
                    Treeview_FillNode(node)
                End If
            Next

            Thistreeview.EndUpdate()

        End Sub
        Sub Treeview_LoadFolderTree(ByVal Path As String, ByVal ThisTreeview As TreeView)

            Dim node As DirectoryNode
            Dim a As Integer

            For a = 1 To UBound(Treeview_Original_path)
               
                If UCase(ThisTreeview.Name) = UCase("Treeview" & CStr(a)) Then
                    Treeview_Original_path(a) = ThisTreeview.Name & "?" & Path
                    Exit For
                End If
            Next
           

            ThisTreeview.Nodes.Clear()

            node = New DirectoryNode(New IO.DirectoryInfo(Path))
            Treeview_FillNode(node)
            ThisTreeview.Nodes.Add(node)

            ThisTreeview.Sort()
            ThisTreeview.TopNode.Expand()

        End Sub

    Sunday, October 02, 2011 6:16 AM
  • x38,

    I'm unsure if this is another question. If the original problem is solved, opening a new thread would be nice, but I've seen you did this already. Don't know if it's related to this message yet.


    Armin
    Sunday, October 02, 2011 11:09 AM
  • For Armin, What I did here was re-arrange your code so it could be used in a module from any form from many treeviews

    Remember if you have 2 treeviews on 3 forms then treeviews must be numbered 1-6

    The problem I have with treeview that nobody seems to be able to answer is that I am making it simple for users to get to my documents by passing "C:\users\myname\My Documents\Pictures" to the tree, not selecting it from a tree populated by expanding "C:\" then selecting the documents folder

    Treeview only shows

    Pictures

                 \ abc

                 \ def

                 \ ghi

    User selects Pictures\abc

    All I get is "Pictures\abc"

    What the treeview shows is waht I want, just the Pictures & child folders, but when I select abc e.node.fullpath only returns "Pictures\abc"

    I know I had the original path when the treeview was populated but it seems that treeview does not retain the original path sent to it, if a user selects a second tree, this path is lost, when user comes back to this tree, it is not re-populated so original path is not available for this tree.

    How do I get the full path? without all the additional code I created

     

    Sunday, October 02, 2011 8:43 PM
  • x38,

    all nodes in the TreeView are of type DirectoryNode. That type has a Directory member of type DirectoryInfo. It contains all the information you need, including the full path.

    Concerning the Module, it's better practice to create your own class that derives from Treeview and put the code there. But it's your decision.


    Armin

    Sunday, October 02, 2011 9:13 PM
  • Thanks for your reply, what you are suggesting "That type has a Directory member of type DirectoryInfo" is not familiar to me, do you have a sample line of code that will retrieve this please.

     

    Monday, October 03, 2011 11:38 AM
  •       Dim node = DirectCast(ctlTreeview.SelectedNode, DirectoryNode)
          MsgBox(node.Directory.FullName)
    
    


    Armin
    Monday, October 03, 2011 2:25 PM
  • Again, excellent answer & removes a lot of my code.

    Thank you for your help, only issue now is trying to clear the selected node, I have tried

    treeview.selectednode.checked=false and also treeview.selectednode.checked=nothing

    It's only a minor issue, but would be nice to solve that as well

    Tuesday, October 04, 2011 5:43 AM
  • ctlTreeview.SelectedNode = Nothing

    Armin
    Tuesday, October 04, 2011 12:01 PM
  • Obviously one of the failings of copying code from another line and also a failing of the compiler to check the code!

    Thanks again

    Tuesday, October 04, 2011 8:30 PM