Home All Groups Group Topic Archive Search About

BackgroundWorker thread locking UI

Author
19 Sep 2006 8:42 PM
John Wright
I have a background worker thread that scans the network listing computers
that are connected.  I have a delegate that I call that invokes a procdure
that loads a dataset with computer names and then attaches it to a dropdown.
When I run it, my UI freezes until it completes.  Any thoughts on how to do
this without freezing the UI?

John


Code

'General Declaration

Private Delegate Sub LoadComputerDelegate()

'called from form load

bgLoadComputers.RunWorkerAsync()



'sub that does the work

Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal e As
System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork

tsStatus.Text = "Loading Computers. Please wait..."

System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))

Invoke(New LoadComputerDelegate(AddressOf LoadComputerDropDown))

End Sub

Private Sub LoadComputerDropDown()

'get the computers on the domain

Try

Dim enTry As DirectoryEntry = New DirectoryEntry(LDAP://[MYDOMAIN])

Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)

mySearcher.Filter = ("(objectClass=Computer)")

Dim resEnt As SearchResult

For Each resEnt In mySearcher.FindAll

Try

Dim tmpID As String = Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)

If Mid(tmpID, 1, 2) = "L1" Then

Dim rwComputer As DataRow

rwComputer = dtComputers.NewRow

rwComputer("Computer Name") =
(Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))

dtComputers.Rows.Add(rwComputer)

End If

tsStatus.Text = "Computers Loaded..."

cboDomainComuters.DataSource = dtComputers

cboDomainComuters.DisplayMember = "Computer Name"

Catch ex As Exception

End Try

Next

Catch ex As Exception

End Try

End Sub

Author
20 Sep 2006 2:58 AM
Jay B. Harlow [MVP - Outlook]
John,
You need to do the actual work in the DoWork event handler.

I would call LoadComputerDropDown directly from DoWork, when
LoadComputerDropDown completes I would Invoke a method on the UI that
"returns" the dataset...

Something like:

    'Code
    Private Delegate Sub LoadComputerDelegate(ByVal table As DataTable)

    'called from form load

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)
        tsStatus.Text = "Loading Computers. Please wait..."
        bgLoadComputers.RunWorkerAsync()
    End Sub


    'sub that does the work

    Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal
e As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
        LoadComputerDropDown()
    End Sub

    Private Sub LoadComputerDropDown()
        Dim dtComputers As New DataTable("Computers")
        dtComputers.Columns.Add("Computer Name", GetType(String))
        'get the computers on the domain
        Try
            Dim enTry As DirectoryEntry = New
DirectoryEntry("LDAP://TSBRADLEY")
            Dim mySearcher As DirectorySearcher = New
DirectorySearcher(enTry)
            mySearcher.Filter = ("(objectClass=Computer)")
            Dim resEnt As SearchResult
            For Each resEnt In mySearcher.FindAll
                Try
                    Dim tmpID As String =
Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
                    If Mid(tmpID, 1, 2) = "L1" Then
                        Dim rwComputer As DataRow
                        rwComputer = dtComputers.NewRow
                        rwComputer("Computer Name") =
(Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
                        dtComputers.Rows.Add(rwComputer)
                    End If
                    Invoke(New LoadComputerDelegate(AddressOf
SetDomainComuters), dtComputers)
                Catch ex As Exception
                    Invoke(New LoadComputerDelegate(AddressOf
SetDomainComuters), dtComputers)
                End Try
            Next
        Catch ex As Exception
            Invoke(New LoadComputerDelegate(AddressOf SetDomainComuters),
dtComputers)
        End Try
    End Sub

    Private Sub SetDomainComuters(ByVal dtComputers As DataTable)
        tsStatus.Text = "Computers Loaded..."
        cboDomainComuters.DataSource = dtComputers
        cboDomainComuters.DisplayMember = "Computer Name"
    End Sub

Note: You should not refer to controls (tsStatus) from the DoWork method.


Show quoteHide quote
"John Wright" <riley_wri***@notmail.com> wrote in message
news:%23YWVgwC3GHA.4172@TK2MSFTNGP05.phx.gbl...
>I have a background worker thread that scans the network listing computers
>that are connected.  I have a delegate that I call that invokes a procdure
>that loads a dataset with computer names and then attaches it to a
>dropdown. When I run it, my UI freezes until it completes.  Any thoughts on
>how to do this without freezing the UI?
>
> John
>
>
> Code
>
> 'General Declaration
>
> Private Delegate Sub LoadComputerDelegate()
>
> 'called from form load
>
> bgLoadComputers.RunWorkerAsync()
>
>
>
> 'sub that does the work
>
> Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal e
> As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
>
> tsStatus.Text = "Loading Computers. Please wait..."
>
> System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
>
> Invoke(New LoadComputerDelegate(AddressOf LoadComputerDropDown))
>
> End Sub
>
> Private Sub LoadComputerDropDown()
>
> 'get the computers on the domain
>
> Try
>
> Dim enTry As DirectoryEntry = New DirectoryEntry(LDAP://[MYDOMAIN])
>
> Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
>
> mySearcher.Filter = ("(objectClass=Computer)")
>
> Dim resEnt As SearchResult
>
> For Each resEnt In mySearcher.FindAll
>
> Try
>
> Dim tmpID As String = Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
>
> If Mid(tmpID, 1, 2) = "L1" Then
>
> Dim rwComputer As DataRow
>
> rwComputer = dtComputers.NewRow
>
> rwComputer("Computer Name") =
> (Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
>
> dtComputers.Rows.Add(rwComputer)
>
> End If
>
> tsStatus.Text = "Computers Loaded..."
>
> cboDomainComuters.DataSource = dtComputers
>
> cboDomainComuters.DisplayMember = "Computer Name"
>
> Catch ex As Exception
>
> End Try
>
> Next
>
> Catch ex As Exception
>
> End Try
>
> End Sub
>
>
>
Author
20 Sep 2006 3:28 AM
Jay B. Harlow [MVP - Outlook]
John,
Doh! You don't need the delegate or the Invoke, the "beauty" of the
background work thread is that it handles the communication between both
threads for you.

Something like:

    'called from form load

    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
        MyBase.OnLoad(e)
        tsStatus.Text = "Loading Computers. Please wait..."
        bgLoadComputers.RunWorkerAsync()
    End Sub



    'sub that does the work

    Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal
e As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
        e.Result = LoadComputerDropDown()
    End Sub

    Private Function LoadComputerDropDown() As DataTable
        Dim dtComputers As New DataTable("Computers")
        dtComputers.Columns.Add("Computer Name", GetType(String))
        'get the computers on the domain
        Dim enTry As DirectoryEntry = New DirectoryEntry("LDAP://[MYDOMAIN])
        Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
        mySearcher.Filter = ("(objectClass=Computer)")
        Dim resEnt As SearchResult
        For Each resEnt In mySearcher.FindAll
            Dim tmpID As String =
Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
            If Mid(tmpID, 1, 2) = "L1" Then
                Dim rwComputer As DataRow
                rwComputer = dtComputers.NewRow
                rwComputer("Computer Name") =
(Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
                dtComputers.Rows.Add(rwComputer)
            End If
        Next
        Return dtComputers
    End Function

    Private Sub bgLoadComputers_RunWorkerCompleted(ByVal sender As Object,
ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles
bgLoadComputers.RunWorkerCompleted
        If e.Error Is Nothing Then
            tsStatus.Text = "Computers Loaded..."
            cboDomainComuters.DataSource = e.Result
            cboDomainComuters.DisplayMember = "Computer Name"
        Else
            MessageBox.Show(e.Error.ToString(), Application.ProductName,
MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub


--
Hope this helps
Jay B. Harlow [MVP - Outlook]
..NET Application Architect, Enthusiast, & Evangelist
T.S. Bradley - http://www.tsbradley.net



Show quoteHide quote
"John Wright" <riley_wri***@notmail.com> wrote in message
news:%23YWVgwC3GHA.4172@TK2MSFTNGP05.phx.gbl...
>I have a background worker thread that scans the network listing computers
>that are connected.  I have a delegate that I call that invokes a procdure
>that loads a dataset with computer names and then attaches it to a
>dropdown. When I run it, my UI freezes until it completes.  Any thoughts on
>how to do this without freezing the UI?
>
> John
>
>
> Code
>
> 'General Declaration
>
> Private Delegate Sub LoadComputerDelegate()
>
> 'called from form load
>
> bgLoadComputers.RunWorkerAsync()
>
>
>
> 'sub that does the work
>
> Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal e
> As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
>
> tsStatus.Text = "Loading Computers. Please wait..."
>
> System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
>
> Invoke(New LoadComputerDelegate(AddressOf LoadComputerDropDown))
>
> End Sub
>
> Private Sub LoadComputerDropDown()
>
> 'get the computers on the domain
>
> Try
>
> Dim enTry As DirectoryEntry = New DirectoryEntry(LDAP://[MYDOMAIN])
>
> Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
>
> mySearcher.Filter = ("(objectClass=Computer)")
>
> Dim resEnt As SearchResult
>
> For Each resEnt In mySearcher.FindAll
>
> Try
>
> Dim tmpID As String = Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
>
> If Mid(tmpID, 1, 2) = "L1" Then
>
> Dim rwComputer As DataRow
>
> rwComputer = dtComputers.NewRow
>
> rwComputer("Computer Name") =
> (Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
>
> dtComputers.Rows.Add(rwComputer)
>
> End If
>
> tsStatus.Text = "Computers Loaded..."
>
> cboDomainComuters.DataSource = dtComputers
>
> cboDomainComuters.DisplayMember = "Computer Name"
>
> Catch ex As Exception
>
> End Try
>
> Next
>
> Catch ex As Exception
>
> End Try
>
> End Sub
>
>
>
Author
20 Sep 2006 3:33 PM
John Wright
Excellent.  This works great.  Thanks.

John
Show quoteHide quote
"Jay B. Harlow [MVP - Outlook]" <Jay_Harlow_***@tsbradley.net> wrote in
message news:CD01013B-EC1D-462D-BEFE-BD0EB87624C3@microsoft.com...
> John,
> Doh! You don't need the delegate or the Invoke, the "beauty" of the
> background work thread is that it handles the communication between both
> threads for you.
>
> Something like:
>
>    'called from form load
>
>    Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
>        MyBase.OnLoad(e)
>        tsStatus.Text = "Loading Computers. Please wait..."
>        bgLoadComputers.RunWorkerAsync()
>    End Sub
>
>
>
>    'sub that does the work
>
>    Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal
> e As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
>        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
>        e.Result = LoadComputerDropDown()
>    End Sub
>
>    Private Function LoadComputerDropDown() As DataTable
>        Dim dtComputers As New DataTable("Computers")
>        dtComputers.Columns.Add("Computer Name", GetType(String))
>        'get the computers on the domain
>        Dim enTry As DirectoryEntry = New
> DirectoryEntry("LDAP://[MYDOMAIN])
>        Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
>        mySearcher.Filter = ("(objectClass=Computer)")
>        Dim resEnt As SearchResult
>        For Each resEnt In mySearcher.FindAll
>            Dim tmpID As String =
> Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
>            If Mid(tmpID, 1, 2) = "L1" Then
>                Dim rwComputer As DataRow
>                rwComputer = dtComputers.NewRow
>                rwComputer("Computer Name") =
> (Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
>                dtComputers.Rows.Add(rwComputer)
>            End If
>        Next
>        Return dtComputers
>    End Function
>
>    Private Sub bgLoadComputers_RunWorkerCompleted(ByVal sender As Object,
> ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles
> bgLoadComputers.RunWorkerCompleted
>        If e.Error Is Nothing Then
>            tsStatus.Text = "Computers Loaded..."
>            cboDomainComuters.DataSource = e.Result
>            cboDomainComuters.DisplayMember = "Computer Name"
>        Else
>            MessageBox.Show(e.Error.ToString(), Application.ProductName,
> MessageBoxButtons.OK, MessageBoxIcon.Error)
>        End If
>    End Sub
>
>
> --
> Hope this helps
> Jay B. Harlow [MVP - Outlook]
> .NET Application Architect, Enthusiast, & Evangelist
> T.S. Bradley - http://www.tsbradley.net
>
>
>
> "John Wright" <riley_wri***@notmail.com> wrote in message
> news:%23YWVgwC3GHA.4172@TK2MSFTNGP05.phx.gbl...
>>I have a background worker thread that scans the network listing computers
>>that are connected.  I have a delegate that I call that invokes a procdure
>>that loads a dataset with computer names and then attaches it to a
>>dropdown. When I run it, my UI freezes until it completes.  Any thoughts
>>on how to do this without freezing the UI?
>>
>> John
>>
>>
>> Code
>>
>> 'General Declaration
>>
>> Private Delegate Sub LoadComputerDelegate()
>>
>> 'called from form load
>>
>> bgLoadComputers.RunWorkerAsync()
>>
>>
>>
>> 'sub that does the work
>>
>> Private Sub bgLoadComputers_DoWork(ByVal sender As System.Object, ByVal e
>> As System.ComponentModel.DoWorkEventArgs) Handles bgLoadComputers.DoWork
>>
>> tsStatus.Text = "Loading Computers. Please wait..."
>>
>> System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2))
>>
>> Invoke(New LoadComputerDelegate(AddressOf LoadComputerDropDown))
>>
>> End Sub
>>
>> Private Sub LoadComputerDropDown()
>>
>> 'get the computers on the domain
>>
>> Try
>>
>> Dim enTry As DirectoryEntry = New DirectoryEntry(LDAP://[MYDOMAIN])
>>
>> Dim mySearcher As DirectorySearcher = New DirectorySearcher(enTry)
>>
>> mySearcher.Filter = ("(objectClass=Computer)")
>>
>> Dim resEnt As SearchResult
>>
>> For Each resEnt In mySearcher.FindAll
>>
>> Try
>>
>> Dim tmpID As String = Mid(resEnt.GetDirectoryEntry.Name.ToString, 4)
>>
>> If Mid(tmpID, 1, 2) = "L1" Then
>>
>> Dim rwComputer As DataRow
>>
>> rwComputer = dtComputers.NewRow
>>
>> rwComputer("Computer Name") =
>> (Mid((resEnt.GetDirectoryEntry().Name.ToString), 4))
>>
>> dtComputers.Rows.Add(rwComputer)
>>
>> End If
>>
>> tsStatus.Text = "Computers Loaded..."
>>
>> cboDomainComuters.DataSource = dtComputers
>>
>> cboDomainComuters.DisplayMember = "Computer Name"
>>
>> Catch ex As Exception
>>
>> End Try
>>
>> Next
>>
>> Catch ex As Exception
>>
>> End Try
>>
>> End Sub
>>
>>
>>
>