We help IT Professionals succeed at work.

Recursive Load of TreeView from an Array of Path-Name Strings

bobcann
bobcann asked
on
I need to insert an array of path names under a root directory into a TreeView. For example:

"C:\DELL\drivers\R162314\DOS\DosDiag"
"C:\DELL\drivers\R162314\DOS\NDIS2"
"C:\DELL\drivers\R162314\DOS\ODI"
"C:\DELL\drivers\R162314\WinVista"
"C:\DELL\drivers\R162314\WinXP"

I'm not able to wrap my head around any examples on the internet.

The "ParsePathString" breaks the path name into the separeate nodes to insert into the treeview.

When stepping through to code that will populate the treeview (using loops for the moment just to see what is happening), the view does not display. All I get is a blank window where the treeview is displayed leaving me blind (please see code). This code is probably incorrect, but I can't tell.

Can anyone offer some advice, code examples, etc. This needs to be finished by the end of the week and I have bearly any .NET experience, which makes it all the worse.

Please let me know if you need any more info. Thanks for your help.

-Bob
Public Class frmHierarchy
    Public Sub PopulateTree(ByVal arrFileInfo() As FilePaths.strucFileInfo)
        Dim clsParsePathString As New ParsePathString
        Dim astrNodes() As String
        Dim idx As Integer
        Dim len As Integer = arrFileInfo.Length

        HierarchyTree.Nodes.Add(New Windows.Forms.TreeNode(mdlManager.strRoot))

        For Each strucFileInfo In arrFileInfo
            astrNodes = clsParsePathString.ParsePathString(arrFileInfo(idx).PathName.ToString, mdlManager.strRoot)

            For idxNode As Integer = 0 To astrNodes.Length
                HierarchyTree.Nodes.Insert(idxNode, New Windows.Forms.TreeNode(arrFileInfo(idxNode).ToString))
            Next
        Next strucFileInfo

    End Sub
End Class

Public Class ParsePathString
    Const charSlash = "\"

    '* parse path name string and roll-up path nodes into array
    Public Function ParsePathString(ByRef strPathName As String, ByRef strRoot As String) As String()
        Dim astr(0) As String
        Dim idx As Integer = 0

        astr(idx) = strRoot
        strRoot = strRoot & charSlash

        strPathName = strPathName.Replace(strRoot, "")
        Dim intEndPos As Integer = strPathName.IndexOf(charSlash)

        Do '* consume string until empty
            idx += 1
            If intEndPos > 0 Then
                ReDim Preserve astr(idx)
                astr(idx) = strPathName.Substring(0, intEndPos)
                strPathName = strPathName.Replace(astr(idx) & charSlash, "")
            Else
                ReDim Preserve astr(idx)
                astr(idx) = strPathName
                strPathName = ""
            End If
            intEndPos = strPathName.IndexOf(charSlash)
        Loop While strPathName.Length > 0

        Return astr
    End Function
End Class

Open in new window

Comment
Watch Question

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009

Commented:
Try this simple example out:
Public Class frmHierarchy

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim paths() As String = {"C:\DELL\drivers\R162314\DOS\DosDiag", _
            "C:\DELL\drivers\R162314\DOS\NDIS2", _
            "C:\DELL\drivers\R162314\DOS\ODI", _
            "C:\DELL\drivers\R162314\WinVista", _
            "C:\DELL\drivers\R162314\WinXP"}

        PopulateTreeView(HierarchyTree, paths)
    End Sub

    Private Sub PopulateTreeView(ByVal TV As TreeView, ByVal paths() As String)
        TV.BeginUpdate()
        TV.Nodes.Clear()
        For Each path As String In paths
            AddPath(TV, Nothing, path)
        Next
        TV.EndUpdate()
        TV.ExpandAll()
    End Sub

    Private Sub AddPath(ByVal TV As TreeView, ByVal parentNode As TreeNode, ByVal path As String)
        If path <> "" Then
            Dim parts As New List(Of String)
            parts.AddRange(path.Split("\"))

            Dim existingNode As TreeNode = Nothing
            If IsNothing(parentNode) Then
                For Each rootNode As TreeNode In TV.Nodes
                    If rootNode.Text = parts(0) Then
                        existingNode = rootNode
                        Exit For
                    End If
                Next
                If IsNothing(existingNode) Then
                    existingNode = TV.Nodes.Add(parts(0))
                End If
            Else
                For Each tn As TreeNode In parentNode.Nodes
                    If tn.Text = parts(0) Then
                        existingNode = tn
                        Exit For
                    End If
                Next
                If IsNothing(existingNode) Then
                    existingNode = parentNode.Nodes.Add(parts(0))
                End If
            End If

            parts.RemoveAt(0)
            AddPath(TV, existingNode, String.Join("\", parts.ToArray))
        End If
    End Sub

End Class

Open in new window

TreeViewWithPaths.jpg
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009

Commented:
Add this snippet if you want to see the full path of the currently selected node:
    Private Sub HierarchyTree_AfterSelect(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles HierarchyTree.AfterSelect
        Label1.Text = e.Node.FullPath
    End Sub

Open in new window

TreeViewWithFullPath.jpg
Ark
CERTIFIED EXPERT

Commented:
A bit shorter :)
Private Sub PopulateTreeView(ByVal tv As TreeView, ByVal paths() As String)
        For Each path As String In paths
            AddPath(tv, path)
        Next
    End Sub

    Private Sub AddPath(ByVal tv As TreeView, ByVal path As String)
        Dim pathBlocks() As String = path.Split("\"c)
        Dim nodes As TreeNodeCollection = tv.Nodes
        For Each block As String In pathBlocks
            If nodes.Find(block, False).Length > 0 Then
                nodes = nodes.Find(block, False)(0).Nodes
            Else
                nodes = nodes.Add(block, block).Nodes
            End If
        Next
    End Sub

Open in new window

Ark
CERTIFIED EXPERT
Commented:
Even shorter :)
Private Sub AddPath(ByVal tv As TreeView, ByVal path As String)
        Dim pathBlocks() As String = path.Split("\"c)
        Dim nodes As TreeNodeCollection = tv.Nodes
        For Each block As String In pathBlocks
            nodes = If(nodes.Find(block, False).Length > 0, nodes.Find(block, False)(0).Nodes, nodes.Add(block, block).Nodes)
        Next
    End Sub

Open in new window

High School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009
Commented:
Thanks Ark.  I like your first one better.

The second one, although shorter, I think loses value as it's too hard to understand.  Looks too much like something a C programmer would do...  ;)

Author

Commented:
Idle_Mind, Ark, thank you. You guys gave me great examples. I rewrote Idle_Mind's code to fit my needs and it works perfectly. Ark, you example came after Idle_Mind's, but is elegant and instructive, as is Idle_Mind's.

Thank you guys for sharing your expertize with me. Best and most impressive response I ever received in EE. If I could give you 5000 points each I would :)

-Bob
Ark
CERTIFIED EXPERT

Commented:
Hello Idle_Mind
Just now recognized that question 'insists' on recursive solution. If so, your answer is more correct, though mine is shorter :)
As for second sample - it shows that all languages became more close :). Plus difference between If and IIF
Regards
Ark
Ark
CERTIFIED EXPERT

Commented:
Thanks for points, glad I could help
To tell the truth, shortest method may not be the best (it just prove I'm too lazy to code large blocks :). In my sample .Find method repeats even if first attempt (with first block) fails. Though .Find with empty collection returns almost immediately, it may take a while for very large path and/or huge array of pathes. More correct code:
   Private Sub AddPath(ByVal tv As TreeView, ByVal path As String)
        Dim pathBlocks() As String = path.Split("\"c)
        Dim nodes As TreeNodeCollection = tv.Nodes
        Dim bFound As Boolean = True
        For Each block As String In pathBlocks
            If bFound AndAlso nodes.Find(block, False).Length > 0 Then
                nodes = nodes.Find(block, False)(0).Nodes
            Else
                nodes = nodes.Add(block, block).Nodes
                bFound=False
            End If
        Next
    End Sub

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
CERTIFIED EXPERT
Top Expert 2009

Commented:
Glad you split the points Bob.  =)

Another difference to point out is that my solution is NOT using 'keyed' nodes thus the necessity for the looping and checking against the .Text property:

                For Each tn As TreeNode In parentNode.Nodes
                    If tn.Text = parts(0) Then

Ark's solution is really compact because he specified a key in the first parameter to the Add() method when he created the nodes:

                nodes = nodes.Add(block, block).Nodes

This allowed him to use the Find() method:

                If nodes.Find(block, False).Length > 0 Then

If you need to specify a key that is DIFFERENT than the value of the node then the more compact option won't work.

Both options are great but the 'best' one may simply be dictated by the requirements of the app.

* I tend to lean towards more verbose and lengthy code so I'm more likely to understand my spaghetti at a later date!  =\

Author

Commented:
Thanks again, idle. I understand the differences that you point out. I'll will study this more carefully when this project is finished-all the managerial hoops jumped :)

I have another question posted, "For Each node In HierarchyTree.Nodes is not stepping through TreeNode."

http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_26204781.html

I'd love to read your thoughts on this.

-Bob