beginInvoke, GUI and thread
Asked Answered
S

2

6

I have application with two thread. One of them (T1) is main GUI form, another (T2) is function working in loop. When T2 gets some information must call function with GUI form. I'm not sure that I do it right.

T2 call function FUNCTION, which update something in GUI form.

  public void f() {
        // controler.doSomething();
  }


 public void FUNCTION() {

    MethodInvoker method = delegate {
            f();
    };

    if ( InvokeRequired ) {
        BeginInvoke( method );
    } else {
            f();
    }
 }

But now I must declare two function. How does it using only one function? Or how does it right.

Sello answered 7/6, 2011 at 16:8 Comment(0)
D
16

You can do this in a single method by calling invoking yourself:

public void Function()
{
     if (this.InvokeRequired)
     {
         this.BeginInvoke(new Action(this.Function));
         return;
     }

     // controller.DoSomething();         
}

Edit in response to comments:

If you need to pass additional arguments, you can do it by using a lambda expression as follows:

public void Function2(int someValue)
{
     if (this.InvokeRequired)
     {
         this.BeginInvoke(new Action(() => this.Function2(someValue)));
         return;
     }

     // controller.DoSomething(someValue);         
}
Deanery answered 7/6, 2011 at 16:13 Comment(11)
Nice pattern. One recursive call to invoke yourself if you were called from a second thread. I would argue that the invocation should be done synchronously, so the call from the second thread (which looks synchronous; just an ordinary method call) would work the same way as if called from the GUI thread, performing the appropriate task before returning.Embarrass
Interesting: I hadn't seen it done like this ... it doesn't cause an endless loop???Hammon
@nirmus: After the closing brace - I thought the goal was to remove the second function ["f()"] - here, it's placed in the main function, after the brace. Basically, if you require an invoke, you invoke yourself, and if not, you can just do whatever you want to do...Deanery
@IAbstract: No. You must put that return; in after the BeginInvoke call, however - without it, you'd have problems ;)Deanery
Nice. But in this solution is small problem. When function has body like this: string f(int a) { return a.toString() } it doesn't work. new Action expect function: void f(). So, how do it?Sello
@Sello - in that case you would change the non-generic Action (which takes no parameters and returns void) to a generic Func<int, string> (which will take one int parameter and return a string parameter). Be aware that there is a limit to what you can plug into a MethodInvoker delegate; you may have to "curry" your invocation to reduce or eliminate the parameters.Embarrass
@Reed: so once this.BeginInvoke( ... ) executes, the InvokeRequired becomes false ... I understand the need for the return ;)Hammon
@nirmus: I edited to display. @KeithS: I personally just use a lambda in that case, as I find it MUCH easier to read. See my edit.Deanery
@IAbstract: Yes, since the BeginInvoke call marshals onto the appropriate synchronization context, it'll no longer require the invoke.Deanery
@Hammon - Correct. When Function is called from a second thread, InvokeRequired is true, and the function schedules a call to itself on the GUI thread. When that call is made and Function executes a second time, InvokeRequired is false because the function is now executing in the GUI thread.Embarrass
Thanks for the info Reed, and @Keith. I had just finished a snippet identical to your second sample ...lol. I love SO ...Hammon
E
3

Looks good to me. You may be able to change the anonymous delegate to a lambda, which is a little cleaner. To get rid of the f() method declaration, you can inline its code into the delegate, then either Invoke the delegate as a MethodInvoker or simply call it like you would any other method:

 public void FUNCTION() {

    MethodInvoker method = ()=> controller.doSomething();

    if ( InvokeRequired ) {
        BeginInvoke( method );
    } else {
            method();
    }
 }
Embarrass answered 7/6, 2011 at 16:14 Comment(1)
It's nice solution. I must learn something about lambda function, because I see that it has interesting possibility. Thanks for help.Sello

© 2022 - 2024 — McMap. All rights reserved.