BackgroundWorker thread locking UI

J

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
 
J

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.


John Wright said:
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
 
J

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



John Wright said:
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
 
J

John Wright

Excellent. This works great. Thanks.

John
Jay B. Harlow said:
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 said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top