Control.Invoke()

  • Thread starter Thread starter JAM
  • Start date Start date
J

JAM

I'm planning to use BacgroundWorker to get some task done. I would
like to update with progress some labels on the main Form.

Let's say I have label1, label2 and label3 on the Form.

BackgroundWorker seem to be working with progress bar from within it's
own thread with no problem. However updating any of the labels causes
exception. I understand that in order to update label1 I have to use
Invoke.

Is it possible to do the following:
(I skip delegate construct here for simplification)

label1.Invoke(updatelabels)

void updatelabels()
{
label1.Text = "abcd";
label2.Text = "aaaa";
label3.Text = "bbbb";
}

or do I have to write separate delegate for each label such as:
(again I skip three delegate constructs here for simplification)

label1.Invoke(updatelabel1);
label2.Invoke(updatelabel2);
label3.Invoke(updatelabel3);

void updatelabel1()
{
label1.Text = "abcd";
}
void updatelabel2()
{
label2.Text = "aaaa";
}
void updatelabel3()
{
label3.Text = "bbbb";
}

JAM
 
JAM said:
I'm planning to use BacgroundWorker to get some task done. I would
like to update with progress some labels on the main Form.

Let's say I have label1, label2 and label3 on the Form.

BackgroundWorker seem to be working with progress bar from within it's
own thread with no problem. However updating any of the labels causes
exception. I understand that in order to update label1 I have to use
Invoke.

The Background Worker updates the UI in the BackgroundWorker_ProgressChanged
method which is called on the UI thread. You can update all your labels
there.

mick
 
JAM said:
I'm planning to use BacgroundWorker to get some task done. I would
like to update with progress some labels on the main Form.

Let's say I have label1, label2 and label3 on the Form.

BackgroundWorker seem to be working with progress bar from within it's
own thread with no problem. However updating any of the labels causes
exception. I understand that in order to update label1 I have to use
Invoke.

As Mick implies, the whole point of using BackgroundWorker is so that
you can avoid having to explicitly use the Control.Invoke() method
yourself. The ProgressChanged and RunWorkerCompleted events are raised
in the same thread that created the BackgroundWorker instance (assuming
it's created in a GUI thread).

So rather than using Invoke() directly, you should put your updating
logic into the event handler for the ProgressChanged event, and make
sure enough information has been passed to the
BackgroundWorker.ReportProgress() method for the event handler to do the
necessary updating.

Since the ProgressChanged event is called on the original GUI thread
that owns the Label controls, in the event handler there's no need to
use Control.Invoke().

That said, your original question is worth discussing on its own merits,
even if in this particular situation you probably don't need to know the
answer:
Is it possible to do the following:
(I skip delegate construct here for simplification)

label1.Invoke(updatelabels)

void updatelabels()
{
label1.Text = "abcd";
label2.Text = "aaaa";
label3.Text = "bbbb";
}

Syntactically, you can cast to MethodInvoker, rather than declaring a
delegate yourself:

label1.Invoke((MethodInvoker)updatelabels);

As for whether you can do everything in one method, the answer is yes.
The Control instance used to call Invoke() is used only to determine
which thread is used to execute the invoked method. As long as all the
Control instances to be updated are owned by the same thread (and in
most applications, they would be), a single call to Invoke(), from any
one of those Control instances, is sufficient.

Once the method is being executed on the correct thread, there are no
additional restrictions on what the method is allowed to do, including
no restriction on which Control instances owned by the executing thread
may be accessed.

Pete
 
Back
Top