views:

357

answers:

5

I am using 5 BackgroundWorker objects running at the same time for a certain purpose, and all of them have to change the same label. How do I do that ?

alt text

How do I modify the form from more than one thread then ? And how do i do it in case i want to change a public string ?

+6  A: 

Use Control.Invoke with a delegate.

In your background worker thread, instead of saying

label4.Text = "Hello";

say

label4.Invoke(new Action(() =>
{
  label4.Text = "Hello";
}
));

Everything inside the { } executes on the control's thread, so you avoid the exception.

This allows you to do arbitrary changes to your user interface from a BackgroundWorker rather than just reporting progress.

RobC
ReportProgress will also let you make arbitrary changes to the UI.
Henk Holterman
how do i invoke it if it's now happening to a public string of my form ?
MarceloRamires
@Henk: ReportProgress will only allow the BackroundWorker to send a single "UserState" object, which must then be interpreted by the ProgressChanged event handler to actually update the UI. What I was trying to say is that with the Invoke() approach you can put the code for the update right inside the method where you create the BackgroundWorker in the first place, leading to more efficient and more readable code. This is a design decision of course, with all the normal tradeoffs.
RobC
as tnt1 says, you should favour BeginInvoke instead of Invoke. There is the possibility of deadlocks using Invoke, because you're waiting for the UI thread to complete the operation - what if it wants a lock your worker thread is holding? BeginInvoke does not wait for the UI thread to return. This is presumably what you want anyway because you don't want your worker to have to wait for the screen to update.
Niall Connaughton
+2  A: 

You could use the ReportProgress method in your BackgroundWorker where you want the label to change and write the actual code in ProgressChanged event handler.

RaYell
the problem is that this is an exception showing label, so it's not everytime that the method ran by the backgroundworker will make any interaction with the form
MarceloRamires
You can use RaYell's suggestion to post information to the GUI which can then do the update itself.
Jon Cage
A: 

Take a look into this answer. It doesn't matter if you have one, five or thousand Worker threads (in meaning of concept).

Oliver
+1  A: 

You should be very wary of calling the synchronous Invoke rather than the async BeginInvoke on a gui. You will soon have an unresponsive and sloppy gui that appears to be struggling to paint itself, as well as potential for deadlocks.
It depends on how often you update it - and does your background thread really need to wait for the gui to have returned? That sounds like a problem with your model.

A: 

As well as Control.BeginInvoke, you can have a look at SynchronizationContext.

When you're creating the BackgroundWorkers, assuming you're creating them from the UI thread, you pass in SynchronizationContext.Current to the workers. When the BackgroundWorkers are ready to invoke something back on the UI thread, they call the Synchronization.Post method on the SynchronizationContext instance passed in when they were created.

There are two good articles on SynchronizationContext here and here.

Niall Connaughton