2

Good Day,

I have two List of objects (say for e.g. MyObjList as new List(of Integer) ) and based on their indices I want to build up a treeview starting from item 0 and end with last item in the list. I want these objects to appear something like below. I can add first node but then after that can't figure how to add next node as child of each previously added node (if that makes sense). Would appreciate your help. I have attached an image to give better understanding of how I want it to look like as against to what I am getting at the moment based on below answers.treeview populated with two lists of objects

0-->
    1
     --> 
        2
         -->
           3--> 
               4


      Dim myObjList As New List(Of integer)
            myObjList.Add("0")
            myObjList.Add("1")
            myObjList.Add("2")
            myObjList.Add("3")
            myObjList.Add("4")

Can we achieve this?

Can we achieve this

DK2014
  • 157
  • 2
  • 16

2 Answers2

3

If I have got this right, you are trying to add Nodes so that the TreeView looks like this:

enter image description here

This is what it would look like manually:

TreeView1.Nodes.Add(list(0).ToString())
TreeView1.Nodes(0).Nodes.Add(list(1).ToString())
TreeView1.Nodes(0).Nodes(0).Nodes.Add(list(2).ToString())
TreeView1.Nodes(0).Nodes(0).Nodes(0).Nodes.Add(list(3).ToString())
TreeView1.Nodes(0).Nodes(0).Nodes(0).Nodes(0).Nodes.Add(list(4).ToString())

This of course is a real pain and isn't scalable. What I would look at instead is recursively adding child Nodes to the TreeView like such:

Public Class Form1

    Dim list As New List(Of Integer)

    Private Sub AddMoreChildren(ByVal parent As TreeNode)

        If parent.Level < list.Count - 1 Then
            Dim child As New TreeNode(list(parent.Level + 1).ToString())

            parent.Nodes.Add(child)

            AddMoreChildren(child)
        End If

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        list.Add(0)
        list.Add(1)
        list.Add(2)
        list.Add(3)
        list.Add(4)

        Dim root As New TreeNode(list.First.ToString())
        AddMoreChildren(root)
        TreeView1.Nodes.Add(root)

    End Sub

End Class

From the code above you will achieve the same result as seen shown in the screenshot.

The beauty of this is that the code will continue to call AddMoreChildren until all items in the List have been added.

Edited to incorporate two lists

If you have two lists then what I would look at doing is bringing them together to create a distinct List using Concat and Distinct.

Note that I have now changed my Lists to be of type String for this example and no longer need to use .ToString when setting the value.

Public Class Form1

    Dim firstList As New List(Of String)
    Dim secondList As New List(Of String)
    Dim mainList As New List(Of String)

    Private Sub AddMoreChildren(ByVal parent As TreeNode)

        If parent.Level < mainList.Count - 1 Then
            Dim child As New TreeNode(mainList(parent.Level + 1))

            parent.Nodes.Add(child)

            AddMoreChildren(child)
        End If

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        firstList.Add("S")
        firstList.Add("A3")
        firstList.Add("U13")
        firstList.Add("ABC")
        firstList.Add("PQ")
        firstList.Add("1234")

        secondList.Add("S")
        secondList.Add("A3")
        secondList.Add("U13")
        secondList.Add("XYZ")
        secondList.Add("ST")
        secondList.Add("5678")

        mainList = firstList.Concat(secondList).Distinct().ToList()

        Dim root As New TreeNode(mainList.First)
        AddMoreChildren(root)
        TreeView1.Nodes.Add(root)

    End Sub

End Class

This will give you the following output:

enter image description here

Edit based on OP's update

This is what the OP is after based on the update:

enter image description here

This requires a little more code and isn't as neat but it does do the job. In this I have to bring in another variable called index. This is purely to keep track of the current index in mainList instead of using If parent.Level.

I also have to manipulate mainList quite a bit so I'll try to explain in bits.

First let's use Intersect. This is used to get a list where values are found in both firstList and secondList leaving us with S, A3 and U13:

Dim root As TreeNode
mainList = firstList.Intersect(secondList).ToList()
root = New TreeNode(mainList.First)

Now that we have these let's go ahead and add them to the TreeView:

index = 1
AddMoreChildren(root)
TreeView1.Nodes.Add(root)

I set index to 1 here because I already have the root node and want to start at A3 when I go into AddMoreChildren. There has also been a slight change to the AddMoreChildren method:

Private Sub AddMoreChildren(ByVal parent As TreeNode)

    If index < mainList.Count Then
        Dim child As New TreeNode(mainList(index).ToString())

        parent.Nodes.Add(child)

        index += 1

        AddMoreChildren(child)
    End If

End Sub

Note the use of index now instead of parent.Level.

Next, since you want to branch out from U13 we need to get the index of this. This is done quite simply:

Dim indexOfLastNode As Integer = mainList.Count - 1

Next we set the U13 as the root node:

root = GetLastAddedChildNode(TreeView1.Nodes(0), indexOfLastNode)

The code for GetLastAddedChildNode is:

Private Function GetLastAddedChildNode(ByVal parentNode As TreeNode,
                                       ByVal level As Integer) As TreeNode

    Dim newNode As New TreeNode

    For Each node As TreeNode In parentNode.Nodes
        If node.Level = level Then
            newNode = node
            Exit For
        End If
        newNode = GetLastAddedChildNode(node, level)
    Next

    Return newNode

End Function

Then we manipulate the mainList so that we get all values from firstList that aren't in secondList. This leaves us with ABC, PQ and 1234. We do this by using Except. We can then call AddMoreChildren and add ABC, PQ and 1234 to U13.

Note, don't forget to reset index to 0 before you call AddMoreChildren so that we can get all the items in mainList added.

We then do the same for the secondList using Except. Here is the full code in one full swoop. It may make more sense:

 Public Class Form1

    Dim firstList As New List(Of String)
    Dim secondList As New List(Of String)
    Dim mainList As New List(Of String)

    Dim index As Integer

    Private Sub AddMoreChildren(ByVal parent As TreeNode)

        If index < mainList.Count Then
            Dim child As New TreeNode(mainList(index).ToString())

            parent.Nodes.Add(child)

            index += 1

            AddMoreChildren(child)
        End If

    End Sub

    Private Function GetLastAddedChildNode(ByVal parentNode As TreeNode,
                                           ByVal level As Integer) As TreeNode

        Dim newNode As New TreeNode

        For Each node As TreeNode In parentNode.Nodes
            If node.Level = level Then
                newNode = node
                Exit For
            End If
            newNode = GetLastAddedChildNode(node, level)
        Next

        Return newNode

    End Function

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        firstList.Add("S")
        firstList.Add("A3")
        firstList.Add("U13")
        firstList.Add("ABC")
        firstList.Add("PQ")
        firstList.Add("1234")

        secondList.Add("S")
        secondList.Add("A3")
        secondList.Add("U13")
        secondList.Add("XYZ")
        secondList.Add("ST")
        secondList.Add("5478")

        Dim root As TreeNode
        mainList = firstList.Intersect(secondList).ToList()
        root = New TreeNode(mainList.First)

        index = 1
        AddMoreChildren(root)
        TreeView1.Nodes.Add(root)

        Dim indexOfLastNode As Integer = mainList.Count - 1

        If TreeView1.Nodes.Count = 1 Then
            root = GetLastAddedChildNode(TreeView1.Nodes(0), indexOfLastNode)

            mainList = firstList.Except(secondList).ToList()
            If root.Text.Equals(firstList(indexOfLastNode)) Then
                index = 0
                AddMoreChildren(root)

                mainList = secondList.Except(firstList).ToList()
                index = 0
                AddMoreChildren(root)
            End If
        End If
    End Sub

End Class

Here is a screenshot of the output:

enter image description here

Bugs
  • 4,356
  • 9
  • 30
  • 39
  • 1
    Hi Jinx88909, yes. That's what I am after. but instead 0,1,...5. etc I have a type of API Object that I would be populating in the treeview. I will try your method as well and let you know how it goes. – DK2014 Jan 30 '17 at 17:23
  • thanks, this works too. just one query, how can I add another list with different values but same parent in this one? Both my lists are basically two Hierarchy Paths with common TopNode. These lists may have common top 2-4 nodes after which they diverge. is that possible. With your and @Pro Grammer's code I can get both paths in Treeview but they appear separate. – DK2014 Jan 30 '17 at 17:33
  • 1
    @DK2014 If this also works, you should click the Up Arrow to UpVote it. Upvotes help other users find good posts. – Ňɏssa Pøngjǣrdenlarp Jan 30 '17 at 17:50
  • 1
    apologies..will try and post some pics to make it more clear. – DK2014 Jan 30 '17 at 21:13
  • @Jinx88909, I have now attached an image to show how its appearing after incorporating your codes and added some explanation on how I want it. Hope its clear this time. – DK2014 Jan 31 '17 at 12:36
  • Thanks. although this one adds the second list unique items as children after having added first list items. I have used your image and made some changes. Is it something we can do. I am not exactly retrieving this objects directly from database. These items are retrieved in our app via API. – DK2014 Jan 31 '17 at 13:36
  • I have added a new image based in the original post, the blue line shows the split where nodes become different. – DK2014 Jan 31 '17 at 15:23
  • 1
    @DK2014 done, think it should be what you are after. It's quite a long answer now so hopefully makes sense. Let me know if you have any further questions. Also note I've deleted comments, just to keep this a little tidier. – Bugs Jan 31 '17 at 16:20
  • 1
    Hi Jinx, great work man. finally made it work.. because I am assigning other properties to treenode like Tag, name(to allow finding node), text and also the image; its took me some time to tweak your new code to my requirements, BUT ITS WORKING!!!!! many thanks.. your help is much appreciated.. now my treeview looks much neat.. – DK2014 Jan 31 '17 at 17:04
  • 1
    @Jinx88909, I am not sure if you were notified before so adding this comment. Also wanted to thank you for the detailed explanation. Its now more clear to me and will be useful in future. cheers.. :-) – DK2014 Jan 31 '17 at 19:47
  • @DK2014 I was :) it's not a problem, had fun putting the code together. Glad you've managed to incorporate into your solution. – Bugs Jan 31 '17 at 19:49
1

Put together this code for you:

Dim tmpNode As TreeNode = Nothing

For Each num In myObjList.Reverse
    Dim newNode = New TreeNode(num.ToString)

    If tmpNode IsNot Nothing Then
        newNode.Nodes.Add(tmpNode)
    End If

    tmpNode = newNode
Next

Goes through the list in reverse and adds each node as a child of the last.

EDIT: Did this one too, doesn't require reversing your list

Dim topNode As TreeNode = Nothing
Dim latestNode As TreeNode = Nothing

For Each num In myObjList
    Dim tmpNode = New TreeNode(num.ToString)

    If myObjList.IndexOf(num) = 0 Then
        topNode = tmpNode
        latestNode = topNode
    Else
        latestNode.Nodes.Add(tmpNode)
        latestNode = tmpNode
    End If
Next
A Friend
  • 2,679
  • 2
  • 11
  • 23
  • Many thanks for quick reply. in your second post,can you tell me what "numlist" is? or is it "myObjList"? Also, where do I specify the Treeview name? sorry for basic questions. – DK2014 Jan 30 '17 at 16:21
  • Oh sorry, I used a temporary list `Dim numList = New List(Of Integer) From {0,1,2,3,4,5,6}`. Let me just edit that out :P As for the treeview name, you would just call TreeView.Nodes.Add() and give it whatever your 0 node is – A Friend Jan 30 '17 at 16:27
  • great. Its working now for me. Just another question. if I now have another list but with different values while the Topnode being same (say 0 in this case), can they both be incorporated in same treeview without having duplicate nodes? – DK2014 Jan 30 '17 at 16:41
  • Absolutely, you would just do the exact same thing, and add it to `TreeView.Nodes` or to `TopNode.Nodes` depending on what you need. Duplicate nodes won't be an issue – A Friend Jan 30 '17 at 16:48