treeview problem, third level index error

Zeusmax

Member
Joined
Oct 10, 2023
Messages
7
Programming Experience
10+
Greetings,
I have a problem with a treeview,
up to 2 levels it works fine, the third level gives index error, can you help me

my tabel : ID_Livello_padre, ID_Livello_figlio, descrizione
VB.NET:
Private Sub Form9_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim mtable2 As New DataTable
        mtable2 = MyDBaseM.Table("SELECT * FROM livelli")
        TreeView1.Nodes.Clear()

        'add i primi livelli
        For Each dr As DataRow In mtable2.Rows
            If dr.Item("ID_Livello_padre").Equals(0) Then
                TreeView1.Nodes.Add(dr.Item("descrizione"))
            End If
        Next

        'add i secondi livelli
        Dim child As Integer = 0
        Dim grandchild As Integer = 0
        For Each dr2 As DataRow In mtable2.Rows

            For Each dr2Child As DataRow In mtable2.Select("ID_Livello_Padre='" & dr2.Item("ID_Livello_figlio") & "'")
                If child < TreeView1.Nodes.Count - 1 Then
                    TreeView1.Nodes(child).Nodes.Add(dr2Child.Item("descrizione"))
                End If

                '   add i terzi livelli
                For Each dr2GrandChild As DataRow In mtable2.Select("ID_Livello_Padre='" & dr2Child.Item("ID_Livello_figlio") & "'")
                    TreeView1.Nodes(child).Nodes(grandchild).Nodes.Add(dr2GrandChild.Item("descrizione"))
                Next
                grandchild = grandchild + 1
            Next
            child = child + 1
        Next
    End Sub
 
Last edited by a moderator:
< should probably be <=, or < ..Nodes.Count but it seems unnecessary, easier if you keep the node refererence that was added, this should work:
VB.NET:
'add i primi livelli
For Each dr As DataRow In mtable2.Rows
    If dr.Item("ID_Livello_padre").Equals(0) Then
        Dim rootnode = TreeView1.Nodes.Add(dr.Item("descrizione"))

        'add i secondi livelli
        For Each drChild As DataRow In mtable2.Select($"ID_Livello_Padre='{dr.Item("ID_Livello_figlio")}'")
            Dim childnode = rootnode.Nodes.Add(drChild.Item("descrizione"))

            'add i terzi livelli
            For Each drGrandChild As DataRow In mtable2.Select($"ID_Livello_Padre='{drChild.Item("ID_Livello_figlio")}'")
                childnode.Nodes.Add(drGrandChild.Item("descrizione"))
            Next
        Next
    End If
Next
 
thanks johnH,
excellent solution
I tried to enter the 4th level but it doesn't work, can you help me again
VB.NET:
        'add i primi livelli
        For Each dr As DataRow In mtable2.Rows
            If dr.Item("ID_Livello_padre").Equals(0) Then
                Dim rootnode = TreeView1.Nodes.Add(dr.Item("descrizione"))

                'add i secondi livelli
                For Each drChild As DataRow In mtable2.Select($"ID_Livello_Padre='{dr.Item("ID_Livello_figlio")}'")
                    Dim childnode = rootnode.Nodes.Add(drChild.Item("descrizione"))

                    'add i terzi livelli
                    For Each drGrandChild As DataRow In  mtable2.Select($"ID_Livello_Padre='{drChild.Item("ID_Livello_figlio")}'")
                        childnode.Nodes.Add(drGrandChild.Item("descrizione"))

                        'add i quarti livelli
                        For Each dr2GrandChild As DataRow In mtable2.Select($"ID_Livello_Padre='{drGrandChild.Item("ID_Livello_figlio")}'")
                            childnode.Nodes.Add(dr2GrandChild.Item("descrizione"))
                        Next
                    Next
                Next
            End If
        Next
 
Notice line 8, Nodes.Add returns the node that was added, this is captured with the local variable childnode, it is further used in the For loop for level 3.
Use the same approach to add level 4 nodes to each level 3 ndoe. Line 12 capture the node and use a loop to add nodes to that.
 
Notice line 8, Nodes.Add returns the node that was added, this is captured with the local variable childnode, it is further used in the For loop for level 3.
Use the same approach to add level 4 nodes to each level 3 ndoe. Line 12 capture the node and use a loop to add nodes to that.


HI,I tried the 4th level like the 3rd but it misreads the parent level at the 4th level and thus the sequence is ruined, I'll give you my solution

'add i primi livelli
For Each dr As DataRow In mtable2.Rows
If dr.Item("ID_Livello_padre").Equals(0) Then
Dim rootnode = TreeView1.Nodes.Add(dr.Item("descrizione"))

'add i secondi livelli
For Each drChild As DataRow In mtable2.Select($"ID_Livello_Padre='{dr.Item("ID_Livello_figlio")}'")
Dim childnode = rootnode.Nodes.Add(drChild.Item("descrizione"))

'add i terzi livelli
For Each drGrandChild As DataRow In mtable2.Select($"ID_Livello_Padre='{drChild.Item("ID_Livello_figlio")}'")
childnode.Nodes.Add(drGrandChild.Item("descrizione"))

'add i quarti livelli
For Each drFourlevel As DataRow In mtable2.Select($"ID_Livello_Padre='{drGrandChild.Item("ID_Livello_figlio")}'")
Dim childnode2 = rootnode.Nodes.Add(drFourlevel.Item("descrizione"))
Next
Next
Next
End If
Next
 
1698001814679.png
 
Like I said, on third level you are not capturing the return of Add.Nodes. It is actually this simple, you just declare a variable and assign the result:
VB.NET:
Dim capturedThird = ...Nodes.Add(...)
Then in fourth level loop use that variable to add nodes:
VB.NET:
capturedThird.Nodes.Add(....)
 
VB.NET:
        'add i primi livelli
        For Each dr As DataRow In mtable2.Rows
            If dr.Item("ID_Livello_padre").Equals(0) Then
                Dim rootnode = TreeView1.Nodes.Add(dr.Item("descrizione"))

                'add i secondi livelli
                For Each drChild As DataRow In mtable2.Select($"ID_Livello_Padre='{dr.Item("ID_Livello_figlio")}'")
                    Dim childnode = rootnode.Nodes.Add(drChild.Item("descrizione"))

                    'add i terzi livelli
                    For Each drGrandChild As DataRow In mtable2.Select($"ID_Livello_Padre='{drChild.Item("ID_Livello_figlio")}'")
                        childnode.Nodes.Add(drGrandChild.Item("descrizione"))

                        'add i quarti livelli
                        For Each drFourlevel As DataRow In mtable2.Select($"ID_Livello_Padre='{drGrandChild.Item("ID_Livello_figlio")}'")
                            Dim childnode2 = rootnode.Nodes.Add(drFourlevel.Item("descrizione"))
                        Next
                    Next
                Next
            End If
        Next
 
At line 12 you are not capturing the return of Nodes.Add for level 3.
 
Look at these three lines:
VB.NET:
Dim rootnode = TreeView1.Nodes.Add(dr.Item("descrizione"))
VB.NET:
childnode.Nodes.Add(drGrandChild.Item("descrizione"))
VB.NET:
Dim childnode2 = rootnode.Nodes.Add(drFourlevel.Item("descrizione"))
Can you see the difference between the second one and the other two?
 
You may also notice that each level loop needs three things as input: the datatable, the parent node and the child ID.
This makes it a candidate for recursion, a method that calls itself with different arguments, which is not uncommon for processing tree structures.

This pseudo code shows how you could organize it:
VB.NET:
sub AddRoots
  for each row in table (where parent id = 0)
    node = treeview add root node (row description)
    AddChildren(table, node, row child id)


sub AddChildren(table, parentNode, id)
  for each row in table (where parent id = id)
    node = parentNode add node (row description)
    AddChildren(table, node, row child id)
 
You may also notice that each level loop needs three things as input: the datatable, the parent node and the child ID.
This makes it a candidate for recursion, a method that calls itself with different arguments, which is not uncommon for processing tree structures.

This pseudo code shows how you could organize it:
VB.NET:
sub AddRoots
  for each row in table (where parent id = 0)
    node = treeview add root node (row description)
    AddChildren(table, node, row child id)


sub AddChildren(table, parentNode, id)
  for each row in table (where parent id = id)
    node = parentNode add node (row description)
    AddChildren(table, node, row child id)


Hi JohnH,thanks again for your patience,I'll put you below your solution adapted to my problem,It seems to work but the tree isn't perfect, I'm attaching my table



treeview:
 Sub AddRoots()
        Dim mtable2 As New DataTable
        mtable2 = MyDBaseM.Table("SELECT * FROM livelli order by ID_Livello_padre, ID_Livello_figlio")

        For Each row In mtable2.Select($"id_livello_padre = '0'")
            Dim node = TreeView1.Nodes.Add(row.Item("descrizione"))
            AddChildren(mtable2, node, row("id_livello_figlio"))
        Next
    End Sub

    Sub AddChildren(table, parentNode, id)
        For Each row2 In table.Select($"id_livello_padre = " & id & "")
            Dim node = parentNode.Nodes.Add(row2.Item("descrizione"))
            AddChildren(table, node, row2("id_livello_figlio"))
        Next
    End Sub
 

Attachments

  • livelli.pdf
    416.6 KB · Views: 7
Back
Top