I have a TreeView control in VS 2010 that I need to be able to INSERT (not add) nodes to. I have stored a unique key in the TAG for each node and know how to find the value of the tag in the tree. However, I can't figure out how to INSERT a NEW node BEFORE or AFTER the node I have found with this tag.

For example, suppose I have the following tree . . .

Item 1
... Item 2
... Item 3
... Item 4
......Item 5
......Item 6
......Item 7
... Item 8
... Item 9
Item 10

The TAG for our example is simply the 1,2,3,4 etc.

If I wanted to INSERT a NEW node at the same level as Item 6 (not a CHILD NODE) but AFTER Item 6 the Tree should look like . . .

Item 1
... Item 2
... Item 3
... Item 4
......Item 5
......Item 6
......Item 6.1
......Item 7
... Item 8
... Item 9
Item 10

I need to be able to do this for any particlular level of the tree (not just the third level where Item 6 is located). Also, Item 6 could have CHILD NODES associated with it but I need to leave those child nodes assoicated with Item 6 and INSERT Item 6.1 below (or above) Item 6 at the same level as Item 6.

Any help someon can pass along would be greatly appreciated.

Thanks

You step through the tree and keep track of the current and previous nodes (I use variables named curr and prev). When you find a node with a value greater than the value of the node you want to insert then you can use the Insert method on the prev node. Try this example. Create a new project. Add a button (btnAdd), a text box (txtAdd) and a treeview (trvTree). Make sure you define a root node (root). Now add the following code

Public Class Form1

    Private Sub btnAdd_Click(sender As System.Object, e As System.EventArgs) Handles btnAdd.Click

        If txtAdd.Text = "" Then Exit Sub

        Dim newnode As New TreeNode
        newnode.Text = txtAdd.Text

        AddNode(trvTree.Nodes(0), newnode)

    End Sub

    Private Sub AddNode(root As TreeNode, newnode As TreeNode)

        Dim curr As TreeNode = Nothing
        Dim prev As TreeNode = root
        Dim i As Integer

        For i = 0 To root.Nodes.Count - 1
            curr = root.Nodes(i)
            If curr.Text > newnode.Text Then Exit For
            prev = curr
        Next

        root.Nodes.Insert(i, newnode)

    End Sub

End Class

Type a word in the textbox and click Add. Keep adding words. They will be placed in the tree in order. This is a simplified example. For the tree in your example there seems to be no obvious algorithm to determine the level of nesting. My example has only one level of nesting.

It seems to me that the easiest way to handle multiple tree levels is to use recursion, but, again, that would rely on there being some way of determining what would require a new level of nesting. For example, why are items 2, 3 and 4 at one level but 5, and 6 (and 6.1 for that matter) at another level?

Thanks for the help but your suggestion doesn't work or solve the original problem.

The issue is being able to INSERT a NODE at the SAME LEVEL as an EXISTING NODE either in front of it or after it. This needs to work regardless at what level of nesting the NODE is at that we want to pick to use for the INSERT. As in my example . . .

Item 1
. . . Item 2
. . . Item 3
. . . Item 4
. . . . . . Item 5
. . . . . . Item 6
. . . . . . Item 6.1
. . . . . . Item 7
. . . Item 8
. . . Item 9
Item 10

. . . I picked ITEM 6 which is nested 2 levels deep. I want to INSERT an item at the SAME LEVEL as Item 6 which we will call Item 6.1. I might also need to insert it in FRONT of Item 6 as in . . .

Item 1
. . . Item 2
. . . Item 3
. . . Item 4
. . . . . . Item 5
. . . . . . Item 6.0
. . . . . . Item 6
. . . . . . Item 7
. . . Item 8
. . . Item 9
Item 10

I have searched the web for a couple of days now and have come close but can't seem to get a handle on how to reference Item 6 and INSERT (not ADD) an Item Above or Below that NODE which is at the same level and not just a CHILD node.

I am using the TAG property to store a unique value in that I can search for to find the node I'm looking for then I want to INSERT a node either before or after the node I find but the important thing is that I want it at the SAME level as the node I just found.

I hope this makes sense.

Thanks for you help.

I'm sure we can do it but I have to know how you decide where to put an item. For example, you add item 4 after item 3 but you add item 5 under item 4. I don't understand how you decide to add after as opposed to under.

I think because of the way I numbered the ITEMS this may have caused some confusion.

Let me try and RENUMBER them this way . . .

Item 1
. . . Item 10
. . . Item 11
. . . Item 12
. . . . . . Item 121
. . . . . . Item 122
. . . . . . Item 123
. . . . . . Item 124
. . . Item 13
. . . Item 14
Item 2

It doesn't matter what the numbers are, but hopefully you can tell by the number of dots in front of the word "Item" that these are INDENTED and are NODES of the Tree. The numbers have nothing to do with anything other than being an example of trying to find one of the existing nodes in the tree.

In my RENUMBERED example if I wanted to find the node labeled Item 123 and I had the value of 123 stored in the TAG property the following code would find the correct NODE (in this case Item 123)

Private Sub btnFindNodeByTag_Click(sender As System.Object, e As System.EventArgs) Handles btnFindNodeByTag.Click

        'look for a node with a tag property value of 123 
        TreeView1.SelectedNode = GetNodeByTag(123), TreeView1.Nodes)
        TreeView1.Select()

End Sub

Private Function GetNodeByTag(ByVal iTagValue As UShort, ByVal parentCollection As TreeNodeCollection) As TreeNode

        Dim ReturnValue As TreeNode
        Dim child As TreeNode

        For Each child In parentCollection 'step through the parentcollection

            If child.Tag = iTagValue Then
                ReturnValue = child
            ElseIf child.GetNodeCount(False) > 0 Then
                ' if there are child items then call this function recursively
                ReturnValue = GetNodeByTag(iTagValue, child.Nodes)
            End If
            If Not ReturnValue Is Nothing Then
                Exit For 'if something was found, exit out of the for loop  
            End If

        Next

        Return ReturnValue

    End Function

This will call the GetNodeByTag function recursively to find the node with a TAG value of 123.

Once I find that node I need to be able to INSERT a node either ABOVE or BELOW the Item 123 node but at the same NODE level. So if I were to INSERT a node above called Item 123A and a node below called Item 123B the tree would look like this when I was finished.

Item 1
. . . Item 10
. . . Item 11
. . . Item 12
. . . . . . Item 121
. . . . . . Item 122
. . . . . . Item 123A
. . . . . . Item 123
. . . . . . Item 123B
. . . . . . Item 124
. . . Item 13
. . . Item 14
Item 2

This EXAMPLE only shows 3 levels but there could be 10+ levels. The LEVEL shouldn't matter. Whatever level the node is at that is located then that's the level I want to INSERT additional NODES Before and/or After the located node.

I hope I've made it a little clearer.

Thanks for you help.

The exact algorithm is extremely important because if you don't know it then you can't program the boundary conditions of the recursion. Your tree starts out with one-digit items at the first level and two-digit items at the second level, then breaks this pattern by having three and four-digit (or character) items at the third level. If you start putting in special cases then it gets messy.

And what do you do if, for example, the first item you want to add is 123? At that point there is no 1 or 12 node to add it under. These things have to be specified completely. I once had a professor who was fond of saying "if you don't know what your program is supposed to do then you'd better not start writing it".

Member Avatar for Unhnd_Exception

Your function returns the correct treenode.

So your function returns a treenode named TreeNode123.

Look at TreeNode123.Parent.Nodes.Insert(TreeNode123.INdex + 1 'or - 1, 'your new treenode')

Just make sure TreeNode123 has a parent. ie its not on level 0

Jim,

Thanks for your help. I think I have tried to explain it as well as I could.

The items you see in my example are the TEXT part of the TreeNode. I have a unique value that is being stored in the TAG property that isn't displayed but is an Unsigned Integer. I can guarantee that this value is unique but not necessarily sequential.

The code I showed you will FIND and SELECT the correct node I'm looking for.

I just cant figure out how to INSERT additional nodes (again, not CHILD nodes) that would appear in the TREE either ABOVE or BELOW the node I was trying to find.

I don't know how to explain it better than that.

Thanks

Member Avatar for Unhnd_Exception

I guess you skipped over my post.

I'll go ahead and change this anyway

Look at TreeNode123.Parent.Nodes.Insert(TreeNode123.INdex + 1 'or TreeNode123.index if you want it before, 'your new treenode')

I believe my earlier example does just that. It creates one level of nodes under the root containing the entered words in sorted order.

Member Avatar for Unhnd_Exception

I believe you believe wrong. I guess my posts are invisible because they do exactly what needs to be done.

I hate feeling like an idiot. Can you please explain to me the difference between what he is asking and what I think he is asking because it is obvious I am completely missing something here.

Member Avatar for Unhnd_Exception

Maybe I'm missing something.

Heres what I think needs to be done. Insert a node in front of or behind an existing node.

The poster has provided a function that returns the node that a new node needs to be inserted above or behind. I'm calling it GetNode because I'm not going to the other page and getting the name.


Dim NodeFound as TreeNode = GetNode.


NodeFound is the node that a new node is supposed to be inserted above or behind.

It doesn't matter if this node is 1 million levels deep, This is the node that the node that another node should be inserted above or behind.

Get the NodeFound's parent node and Insert the new node above or behind it.

Dim ANewNodeToBeInserted as TreeNode("NewNode")

'if behind
NodeFound.Parent.Nodes.Insert(NodeFound.Index, ANewNodeToBeInserted)

'if After
NodeFound.Parent.Nodes.Insert(NodeFound.Index + 1, ANewNodeToBeInserted)

If this is not what is asked then I read the thread wrong.

I see my previous code has some fluff. Typically I step through a collection of nodes using prev, curr and a NextNode method but because Insert requires a node index rather than an actual node I changed a while loop to a for loop but forgot to take out the "prev" code. Usually when looking for a place to insert a node you keep track of the previous node because you don't know where to insert until you have gone one nodoe too far. Thus, you never have to decide "do I insert before or after". You just insert using prev. That's why I am having a problem with the question. Using "prev" you always insert AFTER, like in the example I posted (minus the fluff).

I still maintain that the algorithm (or portion that was posted) makes no sense, at least as it is (incompletely) stated.

Thanks Unhnd Exception ...

Your code worked almost perfectly. One small correction . . .

I needed to add the NEW keyword to the line below.

Dim ANewNodeToBeInserted as NEW TreeNode("NewNode")

I never want to insult anyone who is trying to help but it was obvious that Jim wasn't understanding the question. You got it!

Your code in combination with the GetNodeFromTag function that I posted previously allows me to find any node by the value stored in the TAG property and do exactly what I was trying to do. Jim kept saying that it depended on the algorithm but that wasn't the case. As you correctly indicated, there is no algorithm involved. Once the NODE was found your code allowed me to choose whether I wanted to add a node BEFORE or AFTER the found node.

Jim indicated that he didn't see a need to ever INSERT a value in FRONT of a NODE but that would mean that he would have to understand the use of the TreeView in our application. That wasn't the task at hand.

I want to thank both of you for all your help because if Jim hadn't have tried to help you might not have seen the need to jump in and share your thoughts.

Thanks again . . .

Member Avatar for Unhnd_Exception

Don't forget to mark as solved.

Another thing. If your setting the tag of the nodes to a unique value then you could set the name of the node to the value instead of the tag. You could then do away with your function that searches for the node's tag and replace it with the built in searching.


example:

'If you named the node with the unique value instead of setting
'the tag then you can use Find.
Dim FoundNodes() As TreeNode = TreeView1.Nodes.Find("12345", True)
Dim FoundNode As TreeNode

'Find returned an array of all nodes with the name 12345.
'If unique there will only be one.
If FoundNodes IsNot Nothing AndAlso FoundNodes.Length > 0 Then
    FoundNode = FoundNodes(0)
End If

Clearly I missed the boat on this one. I think I'll reread everything through a few dozen times and go through the code until I get it ;-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.