Sorting Treenodes in treeview  
Author Message
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

I am trying to figure out how to sort the treenodes in a treeview. I am allowing the user to add and update the nodes and their text at runtime. Therefore, I need to implement the Sort procedure in the AfterLabelEdit event. However, there are a few problems I'm not sure how to address. Has anyone done this I can't seem to find a good answer.

My treeview is only 1 level deep. A parent node can only have child nodes and those child nodes cannot have any child nodes. When I add a child node, it adds it at the bottom initially with some default text 'New item' and goes into Edit mode. After I am done editing the text, the AfterLabelEdit event is fired and thats where I save the node to the database and where I would ideally like to resort ONLY that parents nodes that I just added. I don't see a need to resort the whole treeview when I only want to sort the current parent and those nodes.

Does anyone have any thoughts on how to implement this The problem is that the new node Text value is still set to 'New Item' in the AfterLabelEdit event and therefore if I sort it, I will need to use the new value entered, e.Label and not e.Text.

Thoughts or comments



Windows Forms16  
 
 
n0n4m3





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Hi,
the easiest way to sort a treeview is to make your own NodeSorter and set it in the TreeViewNodeSorter property and call Sort() method in the AfterLabelEdit event. Check this thread:
http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=339694&SiteID=1
and this link:
http://msdn2.microsoft.com/en-US/library/system.windows.forms.treeview.treeviewnodesorter.aspx
They might help.


 
 
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

I have actually been trying that and now I remember what my problem was. (Its been a couple of months since I looked at this.)

My problem is that the NodeSorter class works fine if I call it from a button click after I have added the new node. If I try to call it in the AfterLabelEdit event, it sorts the default text of the new node ('New Folder') and makes the last node the text that I entered, overwriting the last node text.

Is there another event that fires after the AfterLabelEdit event that I could use to trigger the NodeSorter automatically when adding new nodes

Thanks,
Greg


 
 
NateV





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Hi there,

Here's something I knocked together....It's not good or fancy like a NodeSorter but it seems to work OK if you put it in the AfterLabelEdit event.

Just one thing, it seems to result in the unusual behaviour of retaining the focus/editability on the node whose editing fired the AfterLabelEdit event. I don't think it's a big deal but it could be annoying....Haven't figured out a workaround yet but might update this post when I do.

Private Sub TreeView1_AfterLabelEdit(ByVal sender As System.Object, ByVal e As System.Windows.Forms.NodeLabelEditEventArgs) Handles TreeView1.AfterLabelEdit
    Dim theParentNode As TreeNode = e.Node.Parent
    Dim indexInCollection As Integer = e.Node.Index
    Dim newPos As Integer = 0
    Dim sortedNodes As List(Of String) = New List(Of String)
    Dim newLabelText As String = e.Label

    'We do not need to fire if nothing has changed (e.Label = e.Node.Text)
    'We do not want infinite firing (IsNothing(e.Label))
    If e.Label = e.Node.Text Or IsNothing(e.Label) Then
        Exit Sub
    End If

    If IsNothing(theParentNode) Then 'Top level node
        For Each node As TreeNode In TreeView1.Nodes
            If node.Index = indexInCollection Then
                sortedNodes.Add(newLabelText)
            Else
                sortedNodes.Add(node.Text)
            End If
    Next
    sortedNodes.Sort()

    newPos = sortedNodes.IndexOf(newLabelText)
    TreeView1.Nodes.Remove(e.Node)
    TreeView1.Nodes.Insert(newPos, e.Node)
   Else '1st level node
        For Each node As TreeNode In theParentNode.Nodes
            If node.Index = indexInCollection Then
                sortedNodes.Add(newLabelText)
            Else
                sortedNodes.Add(node.Text)
            End If
        Next
        sortedNodes.Sort()

        newPos = sortedNodes.IndexOf(newLabelText)
        theParentNode.Nodes.Remove(e.Node)
        theParentNode.Nodes.Insert(newPos, e.Node)
    End If
End Sub

Hope that helps a bit, but sorry if it doesn't


 
 
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Yea, I saw a post very similar to that but didn't like the idea of removing and adding the nodes back but I believe it would work. I may end up trying it if I can't deal with the resort manual button.

What I need is another event like LabelEditedComplete or something that fires after the AfterLabelEdit event so that the sort can take place. Oh well...

Thanks for the help!

Greg


 
 
Peter Huang - MSFT





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Hi Greg,

I think another way was to use a timer.
We can enable the timer after the added the node. And after you sort the treeview, stop the timer.

If you still have any concern, please feel free to post here.

Best regards,
Peter Huang



 
 
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Now that's an interesting approach/hack. I will give it a try and let you know how it works.

Thanks,
Greg


 
 
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

I have this working now where it automatically resorts after adding a node. Here is how.

I initially used a System.Timers.Timer object however, I soon found out that if you start the Timer in the AfterLabelEdit event, and then try to do something in the Timer_Tick event, you will get an exception stating that you cannot make cross-thread calls this way. So...plan B.

I used the BackgroundWorker component. This is the preferred way to implement multithreading. The Worker thread runs your DoWork event and then runs the RunWorkerCompleted event. So, here is my solution:

In the AfterLabelEdit event, after I added my node and saved it to the database, I called mybgWorker.RunWorkerAsync() after all my event processing was done. I then added the following bgWorker events:

Private Sub bgWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
tvMain.TreeViewNodeSorter = New NodeSorter()
End Sub

Private Sub bgWorker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles bgWorker.DoWork
Thread.Sleep(100)
End Sub

And thats it. There is a little flicker when the tree resorts but so far it looks like this will work.

Thoughts or questions

Greg


 
 
jlandheer





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Hi Greg

I also used this approach. I got a few tips for you:

  • In stead of creating a new NodeSorter() you can simply call the Sort() method (assign the NodeSorter after the InitializeComponent() call)
  • Put a Treeview.BeginUpdate() before, and a Treeview.EndUpdate() after calling Treeview.Sort() to prevent flicker and let sorting work faster because the treeview isn't updated when sorting.
  • Is is best to check whether the background worker is busy, before calling RunWorkerAsync(). You can do this by defining a private boolean for a resort after the worker has completed. (A 10th of a second gives this a very small chance, though you never know for sure...)

Hope this helps.

Best regards,


Jeroen Landheer.


 
 
Greg Knierim





PostPosted: Windows Forms General, Sorting Treenodes in treeview Top

Thanks, the BeginUpdate and EndUpdate took care of the flicker problem.

Greg