Background Worker Cross Thread UI problem

J

Jerry Spence1

I am using the BackgroundWorker in VB2005.

I understand the problems of updating a form from a thread, and this can
normally be overcome by doing the updating on the ProgressChanged Event. As
I understand it, this event will operate on the thread that invoked the
original RunWorkerAsync (which may not be the UI thread).

I have a thread, which calls another thread and it is in this thread that I
need to update the form. I have read much about call backs and delegates but
this seems to refer to life before the BackGroundWorker was introduced (whch
I thought did away with all this).

What is the best way for me to update the form in the above circumstances?

-Jerry
 
A

Armin Zingler

Jerry Spence1 said:
I am using the BackgroundWorker in VB2005.

I understand the problems of updating a form from a thread, and this
can normally be overcome by doing the updating on the
ProgressChanged Event. As I understand it, this event will operate
on the thread that invoked the original RunWorkerAsync (which may
not be the UI thread).

I have a thread, which calls another thread and it is in this thread
that I need to update the form. I have read much about call backs
and delegates but this seems to refer to life before the
BackGroundWorker was introduced (whch I thought did away with all
this).

What is the best way for me to update the form in the above
circumstances?

Call the Form's BeginInvoke/Invoke method.


Armin
 
J

Jerry Spence1

Armin Zingler said:
Call the Form's BeginInvoke/Invoke method.


Armin

Thanks. Is my understanding that BackgroundWorker does away with needing
this incorrect then?

-Jerry
 
P

Patrice

This class should handle this for you. Now my understanding is that you are
calling this component from something else than the UI thread which could be
the source of this issue which is perhaps a scenario that is not handled by
this component (you could check the ThreadId to make sure)...
 
B

Bob Altman

Jerry,

BackgroundWorker doesn't change the basic rule that you must not call methods on
a UI element from other than the UI thread. BackgroundWorker just gives you a
convenient way to perform a task on a background thread and to allow that thread
to raise events back to the UI thread.

If you find yourself on a non-UI thread in a context other than a
BackgroundWorker thread and you want to deal with your UI elements then you
still need to call the form's BeginInvoke method to queue the work to the UI
thread.

So, how might you "find yourself on a non-UI thread"? The obvious ways are to
explicitly start some work on a new thread using the Threading namespace or by
calling BeginInvoke on a delegate. Another way would be if your UI thread
called BeginRead or BeginWrite on an object that supports such things, and
specified a callback routine to be executed when the read or write completes.
That routine would find itself running on a non-UI thread.

FWIW, here is the design pattern that I use whenever I write a routine that may
be called on a non-UI thread:

Private Delegate Sub _
MySubDeleg(Arg1 as Integer, arg2 As String)

Sub MySub(Arg1 as Integer, arg2 As String)
If Me.InvokeRequired Then
' Recursively queue the call to the UI thread
Dim deleg As New MySubDeleg(AddressOf MySub)
Me.BeginInvoke(deleg, Arg1, Arg2)
Else
' We're on the UI thread
<Do some work>
End If
End Sub

Note that I've used Me.BeginInvoke, which causes the original call to MySub to
return before the recursive call completes on the UI thread. You can change
BeginInvoke to Invoke, which blocks until the call on the UI thread completes.
But if this whole chain of events began with a UI event then that will cause a
deadlock since the Invoke method won't return until the UI thread is free to
process it, and the UI thread is blocked waiting for the original call to MySub
to return.

Good luck,

Bob
 
J

Jerry Spence1

Thanks for your help Bob. I'm not quite sure where this fits into the
Background worker DoWork routine. Do I simply call MySub from the DoWork
thread and put the actual code that I want run in the <Do some work>
section? I'm still a bit confused how to convert this into a working
example.

Also I'm still not sure whether the ProgressChanged event always runs on the
UI thread, or whether it runs one level up from the DoWork thread (which
might not be the same)

-Jerry
 
B

Bob Altman

Jerry Spence1 said:
Thanks for your help Bob. I'm not quite sure where this fits into the
Background worker DoWork routine. Do I simply call MySub from the DoWork
thread and put the actual code that I want run in the <Do some work> section?
I'm still a bit confused how to convert this into a working example.

When you call the RunWorkerAsync method on a BackgroundWorker object, it raises
the DoWork event on a background thread. The code that called RunWorkerAsync
does *not* block waiting for the DoWork event to complete. Plunk your <do some
work> code into the DoWork event handler. Your <do some work> code is not
allowed to directly access the main form or any of its controls.

One exception to the above rule about not accessing the main form or its
controls is that your <do some work> code is allowed to call the ReportProgress
method on the BackgroundWorker object. This causes the ProgressChanged event to
fire on the UI thread. So any code that runs in the ProgressChanged event
handler is allowed to fiddle with the form and its controls. Note that
BackgroundWorker only raises the ProgressChanged event if you have set the
WorkerReportsProgress property on your BackgroundWorker object to True.

Bob
 
P

Patrice

Sorry I missed that you update the form "out of band" instead of using the
progress event so I'm not sure why you are using the BackgroundWorker
component...

As always the *minimal* amount of code that shows what you are trying to do
could help to understand but I believe the confusion could come from using
the BackgroundWorker for a scenario that doesn't fit... IMO this component
is usefull for doing a simple fire and (almost) forget scenario. If you
really need a more complex interaction behind your background thread and the
UI, I would do this myself...
 

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