2010-02-06 7 views
31

Ich habe diese kleine Methode, die threadsicher sein soll. Alles funktioniert, bis ich möchte, dass es einen Rückgabewert anstelle von void hat. Wie bekomme ich den Rückgabewert, wenn BeginInvoke aufgerufen wird?Wie bekomme ich den Rückgabewert, wenn BeginInvoke/Invoke aufgerufen wird in C#

public static string readControlText(Control varControl) { 
     if (varControl.InvokeRequired) { 
      varControl.BeginInvoke(new MethodInvoker(() => readControlText(varControl))); 
     } else { 
      string varText = varControl.Text; 
      return varText; 
     } 

    } 

Edit: Ich denke, die BeginInvoke ist in diesem Fall nicht nessecary als i Wert von GUI muß, bevor der Thread fortgesetzt werden kann. Die Verwendung von Invoke ist also ebenfalls gut. Keine Ahnung, wie man es im folgenden Beispiel verwendet, um einen Wert zurückzugeben.

private delegate string ControlTextRead(Control varControl); 
    public static string readControlText(Control varControl) { 
     if (varControl.InvokeRequired) { 
      varControl.Invoke(new ControlTextRead(readControlText), new object[] {varControl}); 
     } else { 
      string varText = varControl.Text; 
      return varText; 
     } 

    } 

aber nicht sicher, wie Wert zu erhalten, dass Code entweder mit;)

+0

Wenn Sie mit dem Wert arbeiten müssen, der von einem Aufruf zurückgegeben wird, muss das sein, da Sie ein "Continuation Passing Style" -Muster benötigen. Was mit 'async',' await' und 'Task' gemildert werden kann. –

Antwort

49

Sie müssen Invoke() aufrufen, damit Sie auf die Rückkehr der Funktion warten und ihren Rückgabewert erhalten können. Sie benötigen außerdem einen anderen Delegattyp. Dies sollte funktionieren:

public static string readControlText(Control varControl) { 
    if (varControl.InvokeRequired) { 
    return (string)varControl.Invoke(
     new Func<String>(() => readControlText(varControl)) 
    ); 
    } 
    else { 
    string varText = varControl.Text; 
    return varText; 
    } 
} 
1

Wenn Sie einen Rückgabewert von Ihnen Methode wollen, sollten Sie nicht Asynchron-Version der Methode verwenden, sollten Sie .Invoke(...) verwenden . Was synchron ist, das heißt, es wird Ihren Delegaten ausführen und wird nicht zurückkehren, bis es abgeschlossen ist. In Ihrem Beispiel, wie es jetzt ist, wird BeginInvoke die Anfrage senden, um Ihren Delegierten auszuführen, und sofort zurückkehren. Also gibt es nichts zurückzugeben.

+0

Es kann Invoke oder BeginInvoke sein, solange ich Wert zurückbekomme. Alles, was ich brauche, ist Wert von Combobox oder Textbox von anderen Thread zu lesen. – MadBoy

1

Ist etwas wie das, was Sie wollten?

+0

Nicht ganz. Ich denke, die Verwendung von BeginInvoke ist nicht notwendig, da ich nur Wert von ComboBox oder TextBox lesen möchte und dieser Wert wichtig ist, um andere Befehle auszuführen. So könnte ich es in Invoke verwenden. Nur nicht sicher, wie ich Ihr Beispiel in meinem Fall verwenden könnte, wo der Hauptzweck es ist, Methode von einem anderen Thread aufzurufen, gui-Wert zu lesen und zurück zu mir zu kommen, damit Programm weiter gehen kann. – MadBoy

3
public static string readControlText(Control varControl) 
{ 
    if (varControl.InvokeRequired) 
    { 
     string res = ""; 
     var action = new Action<Control>(c => res = c.Text); 
     varControl.Invoke(action, varControl); 
     return res; 
    } 
    string varText = varControl.Text; 
    return varText; 
} 
+0

Sieht ähnlich wie Nobugz-Lösung aus, aber sein Aussehen ist sauberer für mich :-) – MadBoy

+0

Ja, ich stimme zu. Als ich meine Lösung gepostet habe, sehe ich noch keine nobugz-Lösung :) –

16

EndInvoke verwendet werden kann, einen Rückgabewert von einem BeginInvoke Anruf zu bekommen. Zum Beispiel:

public static void Main() 
    { 
     // The asynchronous method puts the thread id here. 
     int threadId; 

     // Create an instance of the test class. 
     AsyncDemo ad = new AsyncDemo(); 

     // Create the delegate. 
     AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod); 

     // Initiate the asychronous call. 
     IAsyncResult result = caller.BeginInvoke(3000, 
      out threadId, null, null); 

     Thread.Sleep(0); 
     Console.WriteLine("Main thread {0} does some work.", 
      Thread.CurrentThread.ManagedThreadId); 

     // Call EndInvoke to wait for the asynchronous call to complete, 
     // and to retrieve the results. 
     string returnValue = caller.EndInvoke(out threadId, result); 

     Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".", 
      threadId, returnValue); 
    } 
} 
+0

Insgesamt gutes Beispiel, obwohl in meinem Fall die nobugz-Lösung perfekt ist und genau das, was benötigt wurde. – MadBoy

0
delegate string StringInvoker(); 
    string GetControlText() 
    { 
     if (control.InvokeRequired) 
     { 
      string controltext = (string)control.Invoke(new StringInvoker(GetControlText)); 
      return(controltext); 
     } 
     else 
     { 
      return(control.Text); 
     } 
    } 

// einfache & elegant, aber es ist notwendig, für einen anderen Thread zu warten Delegierten auszuführen; Wenn Sie jedoch ohne die Ergebnisse nicht fortfahren können ...