Results 1 to 18 of 18

Thread: [RESOLVED] Expand Treeview using Background Worker

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Resolved [RESOLVED] Expand Treeview using Background Worker

    Hi,
    I would like to run the below code in Background worker as it sometimes freezes up. When I run in BGW Dowork I get an illegal cross thread operation. Could someone assist in helping me run the populateChildNodes sub in background worker? I read the article in the Codebank but still unable to get this to work. Any help will greatly be appreciated. Thank in advance

    PHP Code:
       Private Sub TreeView1_AfterSelect(sender As ObjectAs TreeViewEventArgsHandles TreeView1.AfterSelect

            
    If e.Node.Nodes.Count 0 Then

               BackgroundWorker1
    .RunWorkerAsync()

                
    Call populateChildNodes(e.Node)
            
    End If

       
    End Sub 

    PHP Code:
       Private Sub populateChildNodes(parentNode As TreeNode)
            
    ToolStripProgressBar1.Visible True
            ToolStripStatusLabel1
    .Visible True
            ToolStripStatusLabel1
    .Text "starting..."
            
    Application.DoEvents()

            
    Dim LDAP As DirectoryEntry CType(parentNode.TagDirectoryEntry)

                For 
    Each child As DirectoryEntry In LDAP.Children
                    Dim childName 
    As String GetName(child.Name)
                    
    Dim childNode As New TreeNode(childName)
                    
    childNode.Tag child
                    parentNode
    .Nodes.Add(childNode)
                
    Next

            parentNode
    .Expand()
            
    ToolStripProgressBar1.Visible False
            ToolStripStatusLabel1
    .Text "Done"
        
    End Sub 
    PHP Code:
       Private Sub BackgroundWorker1_DoWork(sender As ObjectAs System.ComponentModel.DoWorkEventArgsHandles BackgroundWorker1.DoWork

       
    ' How do I run populateChildNodes(parentNode As TreeNode) so it does not give the illegal crossthread operation
        End Sub 

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Expand Treeview using Background Worker

    ' How do I run populateChildNodes(parentNode As TreeNode) so it does not give the illegal crossthread operation
    You don't. A BackgroundWorker is for background work and anything to do with a control is inherently foreground work, so cannot be done in or from the DoWork event handler of a BackgroundWorker. What you do is separate out the background work and the foreground work and then only do the background work in the DoWork event handler. When that's done, the RunWorkerCompleted event is raised and you can update the control(s) on the UI thread.

    So, the steps are as follows:

    1. Get any data from the UI that will be required by the background task.
    2. Call RunWorkerAsync and pass in the data retrieved in step 1.
    3. Handle the DoWork event.
    4. Retrieve the data passed in in step 2.
    5. Perform the background work using the data retrieved in step 4.
    6. Pass out the result of the background work.
    7. Handle the RunWorkerCompleted event.
    8. Retrieve the data passed out in step 6.
    9. Update the UI using the data retrieved in step 8.

    For an example, follow the CodeBank link in my signature and check out my thread on Using The BackgroundWorker. In your case, the argument you pass in will be the Tag of the parent node and the result will be an array of TreeNode objects. You can then call AddRange to add that array of nodes to the parent in the RunWorkerCompleted event handler.

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: Expand Treeview using Background Worker

    I've been working on it for a couple of days to no avail. The below is the best I came up with. Could someone help in getting this to work. Thanks in advance.

    PHP Code:
        Private Sub populateChildNodes(parentNode As TreeNode)
            
    ToolStripProgressBar1.Visible True
            ToolStripStatusLabel1
    .Visible True
            ToolStripStatusLabel1
    .Text "Starting..."

              
    Run_ON_BGW(parentNode)

            
    BackgroundWorker1.RunWorkerAsync()



            
    ToolStripProgressBar1.Visible False
            ToolStripStatusLabel1
    .Text "Done"
        
    End Sub 
    PHP Code:
        Sub Run_ON_BGW(parentNode As TreeNode)

            
    Dim LDAP As DirectoryEntry CType(parentNode.TagDirectoryEntry)

            For 
    Each child As DirectoryEntry In LDAP.Children
                Dim childName 
    As String GetName(child.Name)
                
    Dim childNode As New TreeNode(childName)
                
    childNode.Tag child
                parentNode
    .Nodes.Add(childNode)
            
    Next
            parentNode
    .Expand()
        
    End Sub 
    PHP Code:
     Private Sub BackgroundWorker1_DoWork(sender As ObjectAs System.ComponentModel.DoWorkEventArgsHandles BackgroundWorker1.DoWork

            Run_ON_BGW
    (parentNode As TreeNode)

            
    Dim nodeList As List(Of TreeNode) = DirectCast(e.Result, List(Of TreeNode))
            
    TreeView1.Nodes.AddRange(nodeList.ToArray())

        
    End Sub 

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Expand Treeview using Background Worker

    I SPECIFICALLY said that you can't touch controls in the DoWork event handler and your code is adding nodes to the TreeView in the DoWork event handler. I can't see where you've even tried to do what I suggested. Did you check out my examples in the CodeBank? One of them (post #4) shows how to gather items in the DoWork event handler and then add them to a ListBox in the RunWorkerCompleted event handler. Why can't you do the same thing with TreeNodes and a TreeView?

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: Expand Treeview using Background Worker

    I did check your CodeBank examples and learn some cool stuff to the point I went back and update some of my older projects. I however am finding this to be a issue. Perhaps I'm overthinking it.

  6. #6
    Frenzied Member
    Join Date
    Oct 2012
    Location
    Tampa, FL
    Posts
    1,187

    Re: Expand Treeview using Background Worker

    Quote Originally Posted by UCPocoAPoco View Post
    I did check your CodeBank examples and learn some cool stuff to the point I went back and update some of my older projects. I however am finding this to be a issue. Perhaps I'm overthinking it.
    Perhaps you are, you cannot work with the TreeView at all in the background worker.

    Code:
            TreeView1.Nodes.AddRange(nodeList.ToArray())
    You cannot do anything to it. Your code shows you doing stuff to it. You can only prepare the data, then pass it to the worker completed event. In the worker completed event you can finally work with the treeview.

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,297

    Re: Expand Treeview using Background Worker

    Quote Originally Posted by UCPocoAPoco View Post
    Perhaps I'm overthinking it.
    Perhaps the opposite. There is one rule when using a BackgroundWorker: DO NOT touch the UI in the DoWork event handler. If you're breaking that rule then you're not over-thinking anything. Read the words: do not touch the TreeView in the DoWork event handler or any method called from the DoWork event handler. The ONLY thing you should be doing in the DoWork event handler is creating the TreeNodes that you intend to add.

    If you need data from the TreeView to do that, get it BEFORE you call RunWorkerAsync and pass it in. My CodeBank thread demonstrates that. If you need to update the TreeView afterwards, pass the data out of the DoWork event handler into the RunWorkerCompleted event handler and update it there. My CodeBank thread demonstrates how to do that.

  8. #8
    PowerPoster
    Join Date
    Sep 2006
    Location
    Egypt
    Posts
    2,579

    Re: Expand Treeview using Background Worker

    @UCPocoAPoco

    Here is a working list demonstrate how to call PopulateChildNodes from BackgroundWorker1_DoWork, try to adapt this code to work with your project.
    Code:
    Option Strict On
    Option Explicit On
    
    Imports System.IO
    Imports System.ComponentModel
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TreeView1.Nodes.Add("C:\").Tag = "C:\"
            TreeView1.Nodes.Add("D:\").Tag = "D:\"
        End Sub
    
        Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
            BackgroundWorker1.RunWorkerAsync(e.Node.Tag)
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            e.Result = PopulateChildNodes(CStr(e.Argument))
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Dim n As List(Of TreeNode) = CType(e.Result, List(Of TreeNode))
            TreeView1.SelectedNode.Nodes.AddRange(n.ToArray)
        End Sub
    
        Private Function PopulateChildNodes(strPath As String) As List(Of TreeNode)
            Dim r As New List(Of TreeNode)
            Dim n As TreeNode
    
            Dim Dirs() As String = IO.Directory.GetDirectories(strPath, "*.*", IO.SearchOption.TopDirectoryOnly)
    
            For j = 0 To Dirs.Length - 1
                n = New TreeNode(IO.Path.GetFileName(Dirs(j))) ' Show folder name only
                n.Tag = Dirs(j) ' Save folder full path in Tag
                r.Add(n)
            Next
    
            Return r
    
        End Function
    
    End Class



  9. #9
    PowerPoster
    Join Date
    Sep 2006
    Location
    Egypt
    Posts
    2,579

    Re: Expand Treeview using Background Worker

    The same list with showing the progress of the background operation.

    Code:
    Option Strict On
    Option Explicit On
    
    Imports System.IO
    Imports System.ComponentModel
    
    Public Class Form1
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            TreeView1.Nodes.Add("C:\").Tag = "C:\"
            TreeView1.Nodes.Add("D:\").Tag = "D:\"
    
            BackgroundWorker1.WorkerReportsProgress = True
    
        End Sub
    
        Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
            ProgressBar1.Show()
            BackgroundWorker1.RunWorkerAsync(e.Node.Tag)
            MessageBox.Show("TreeView1 is populating in a Background thread")
    
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            e.Result = PopulateChildNodes(CStr(e.Argument))
        End Sub
    
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            ProgressBar1.Value = e.ProgressPercentage
        End Sub
    
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            Dim n As List(Of TreeNode) = CType(e.Result, List(Of TreeNode))
            TreeView1.SelectedNode.Nodes.AddRange(n.ToArray)
            ProgressBar1.Hide()
        End Sub
    
        Private Function PopulateChildNodes(strPath As String) As List(Of TreeNode)
            Dim r As New List(Of TreeNode)
            Dim n As TreeNode
    
            Dim Dirs() As String = IO.Directory.GetDirectories(strPath, "*.*", IO.SearchOption.TopDirectoryOnly)
            Dim t As Integer = Dirs.Length
    
            For j = 0 To Dirs.Length - 1
                n = New TreeNode(IO.Path.GetFileName(Dirs(j))) ' Show folder name only
                n.Tag = Dirs(j) ' Save folder full path in Tag
                r.Add(n)
                BackgroundWorker1.ReportProgress(CInt((j / t) * 100))
                Threading.Thread.Sleep(100) ' Delay to simulate a more complicated calculation.
            Next
    
            Return r
    
        End Function
    
    End Class



  10. #10

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: Expand Treeview using Background Worker

    Thanks 4x2y for the sample. However I am having an issue with the below. Been over a week and still can't get it working in a BGW.


    PHP Code:
    Private Sub RadioButton1_CheckedChanged(sender As ObjectAs EventArgsHandles RadioButton1.CheckedChanged

            Dim parentNode 
    As New TreeNode("LocationA")

            If 
    IsNothing(parentNode) = False Then
                TreeView1
    .Nodes.Clear()
                
    TreeView1.Nodes.Remove(parentNode)
            
    End If

            
    Dim LDAP As New DirectoryEntry("LDAP://company.com")

            
    parentNode.Tag LDAP
            TreeView1
    .Nodes.Add(parentNode)
            
    TreeView1.SelectedNode parentNode

        End Sub 

    PHP Code:
     Private Sub TreeView1_AfterSelect(sender As ObjectAs TreeViewEventArgsHandles TreeView1.AfterSelect

            
    If e.Node.Nodes.Count 0 Then

                BackgroundWorker1
    .RunWorkerAsync(e.Node)
            
    End If

        
    End Sub 
    I am getting an error at the do work Error Value of type 'String' cannot be converted to 'System.Windows.Forms.TreeNode'.


    PHP Code:
    Private Sub BackgroundWorker1_DoWork(sender As ObjectAs System.ComponentModel.DoWorkEventArgsHandles BackgroundWorker1.DoWork

            e
    .Result populateChildNodes(CStr(e.Argument))



        
    End Sub 

    PHP Code:
    Private Sub BackgroundWorker1_RunWorkerCompleted(sender As ObjectAs System.ComponentModel.RunWorkerCompletedEventArgsHandles BackgroundWorker1.RunWorkerCompleted

            Dim n 
    As List(Of TreeNode) = CType(e.Result, List(Of TreeNode))
            
    TreeView1.SelectedNode.Nodes.AddRange(n.ToArray)

        
    End Sub 

    PHP Code:
    Private Sub populateChildNodes(parentNode As TreeNode)

            
            
    ToolStripStatusLabel1.Text "Starting..."
            
    Application.DoEvents()

            
    Dim LDAP As DirectoryEntry CType(parentNode.TagDirectoryEntry)

            For 
    Each child As DirectoryEntry In LDAP.Children

                Dim childName 
    As String GetName(child.Name)
                
    Dim childNode As New TreeNode(childName)
                
    childNode.Tag child
                parentNode
    .Nodes.Add(childNode)

            
    Next

            parentNode
    .Expand()

        
    End Sub 
    Last edited by UCPocoAPoco; May 16th, 2015 at 11:46 AM.

  11. #11
    PowerPoster
    Join Date
    Sep 2006
    Location
    Egypt
    Posts
    2,579

    Re: Expand Treeview using Background Worker

    Try this, i hope it works for you!
    vb Code:
    1. Option Strict On
    2. Option Explicit On
    3.  
    4. Public Class Form1
    5.  
    6.     Private Sub TreeView1_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles TreeView1.AfterSelect
    7.         If e.Node.Nodes.Count = 0 Then
    8.             ToolStripStatusLabel1.Text = "Starting..." ' Moved here in order to not touch any UI control in the background thread.
    9.             BackgroundWorker1.RunWorkerAsync(e.Node.Tag)
    10.         End If
    11.     End Sub
    12.  
    13.     Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    14.         e.Result = PopulateChildNodes(CType(e.Argument, DirectoryEntry))
    15.     End Sub
    16.  
    17.     Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    18.         Dim n As List(Of TreeNode) = CType(e.Result, List(Of TreeNode))
    19.         TreeView1.SelectedNode.Nodes.AddRange(n.ToArray)
    20.         ToolStripStatusLabel1.Text = "Finished..."
    21.     End Sub
    22.  
    23.     Private Sub RadioButton1_CheckedChanged(sender As Object, e As EventArgs) Handles RadioButton1.CheckedChanged
    24.  
    25.         Dim parentNode As New TreeNode("LocationA")
    26.  
    27.         If IsNothing(parentNode) = False Then
    28.             TreeView1.Nodes.Clear()
    29.             TreeView1.Nodes.Remove(parentNode)
    30.         End If
    31.  
    32.         Dim LDAP As New DirectoryEntry("LDAP://company.com")
    33.  
    34.         parentNode.Tag = LDAP
    35.         TreeView1.Nodes.Add(parentNode)
    36.         TreeView1.SelectedNode = parentNode
    37.  
    38.     End Sub
    39.  
    40.     Private Function PopulateChildNodes(LDAP As DirectoryEntry) As List(Of TreeNode)
    41.         Dim r As New List(Of TreeNode)
    42.  
    43.         For Each child As DirectoryEntry In LDAP.Children
    44.             Dim childName As String = GetName(child.Name)
    45.             Dim childNode As New TreeNode(childName)
    46.             childNode.Tag = child
    47.             r.Add(childNode)
    48.         Next
    49.  
    50.         Return r
    51.  
    52.     End Function
    53. End Class



  12. #12

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: Expand Treeview using Background Worker

    You sir are 4x2y Times 10. My project is now working beautifully. Thank you AGAIN for your help.

  13. #13
    PowerPoster
    Join Date
    Sep 2006
    Location
    Egypt
    Posts
    2,579

    Re: Expand Treeview using Background Worker

    Quote Originally Posted by UCPocoAPoco View Post
    My project is now working beautifully.
    Nice to here that,
    Final step, mark this thread as RESOLVED



  14. #14

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: Expand Treeview using Background Worker

    Sure. How would one do that? . Found it Thanks

    How do I do it?

    To mark your thread as resolved, find the Thread Tools link on the bar above the first post. Click on and a menu will drop down showing you some options. From these choose "Mark Thread Resolved" which is the bottom-most option.
    Last edited by UCPocoAPoco; May 16th, 2015 at 04:06 PM.

  15. #15
    Bad man! ident's Avatar
    Join Date
    Mar 2009
    Location
    Cambridge
    Posts
    5,398

    Re: [RESOLVED] Expand Treeview using Background Worker

    You could add 1k entrys in 0.1 of a second. So why use a secondary thread? Not that you would add 1k items.

  16. #16

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: [RESOLVED] Expand Treeview using Background Worker

    I originally thought the same. If there are OU's that have around 3K workstations or more, it takes about 3 to 18 seconds to populate and freezes upon moving or selecting a different OU. All other OU's takes a few seconds or less to populate. Using a BGW makes a big difference from my testing.

  17. #17
    Bad man! ident's Avatar
    Join Date
    Mar 2009
    Location
    Cambridge
    Posts
    5,398

    Re: [RESOLVED] Expand Treeview using Background Worker

    18 seconds to populate how many entrys? BGW cant speed up adding of entrys :/

  18. #18

    Thread Starter
    Lively Member
    Join Date
    Jan 2012
    Posts
    86

    Re: [RESOLVED] Expand Treeview using Background Worker

    Agree. It helps in two different ways.

    1) The form is not unresponsive with OU's that has many computer account.

    2) If an OU with many computer accounts is selected inadvertently, you will have to wait for it to populate before selecting a different OU. With the BGW, it does not cause an issue as the GUI is responsive allowing you to select a different OU or as fast as you can press the down arrow\ Up arrow.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width