views:

72

answers:

2

Hi, how do you update a win forms control (ex. label, progress bar) from another class which created the GUI but not in the creating thread? (for example, an event handler of Program.cs)

I've found several posts regarding updating GUI from another thread using Invoke() method, but what i've found so far only works if the codes are written in the same class as the form

http://www.yoda.arachsys.com/csharp/threads/winforms.shtml

+3  A: 

You need to call the Invoke method on the form. For example:

private void someMethod() {
    myOtherForm.Invoke(new MethodInvoker(delegate() {
        // update things in myOtherForm here
    }));
}

If you don't need the updates to be finished before returning back to the method, you should use BeginInvoke instead of Invoke.

icktoofay
Augh, accidentally pressed tab, then enter, and it submitted the answer while I was typing...
icktoofay
+2  A: 

Well, there are two separate issues here:

  • Updating the UI from a different class
  • Updating the UI from a different thread

The two are almost completely orthogonal. Once you've solved each of them in isolation, you can put the two together.

If there are well-understood ways in which the UI needs to be changed (e.g. updating the text in a status bar or something like that) I would write methods in the UI class itself to do that, and just call those methods from the other class. Alternatively, you can expose the individual control of the UI - preferably through properties - and then use Control.Invoke in the normal way from the other class, e.g.

MethodInvoker action = () => form.StatusLabel.Text = "Finished";
form.BeginInvoke(action);

So long as you call Invoke on a control which "lives" on the same thread as all the controls you touch, it doesn't matter which one you use... so an alternative could be:

Label label = form.StatusLabel;
MethodInvoker action = () => label.Text = "Finished";
label.BeginInvoke(action);

One difference here is that in this latter code, the StatusLabel property is being evaluated in the worker thread - which could lead to race conditions if your UI is changing it to refer to different labels at different times. I would generally prefer the first approach.

(I agree with icktoofay's comment about BeginInvoke being preferable unless you really need to wait, by the way... although you do then need to be careful about changes to any variables captured by anonymous functions.)

Jon Skeet