2010-02-06 3 views
31

J'ai cette petite méthode qui est censée être thread-safe. Tout fonctionne jusqu'à ce que je le veuille avoir la valeur de retour au lieu du vide. Comment puis-je obtenir la valeur de retour lorsque BeginInvoke est appelé?Comment obtenir la valeur de retour lorsque BeginInvoke/Invoke est appelé en C#

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

    } 

Edit: Je suppose avoir BeginInvoke n'est pas nessecary dans ce cas, comme je l'ai besoin valeur de GUI avant que le thread peut continuer. Donc, en utilisant Invoke est bon aussi. Juste aucune idée comment l'utiliser dans l'exemple suivant pour retourner la valeur.

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; 
     } 

    } 

Mais pas sûr comment obtenir la valeur en utilisant ce code soit;)

+0

Si vous devez travailler avec la valeur renvoyée par un appel, cela doit être dû au fait que vous avez besoin d'un modèle de "style de transition continue". Ce qui peut être allégé avec 'async',' await' et 'Task'. –

Répondre

49

Vous devez appeler() pour attendre que la fonction renvoie et obtenir sa valeur de retour. Vous aurez également besoin d'un autre type de délégué. Cela devrait fonctionner:

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

Si vous voulez une valeur de retour de votre méthode, vous ne devriez pas utiliser la version async de la méthode, vous devez utiliser .Invoke(...) . Ce qui est synchrone, c'est-à-dire exécutera votre délégué, et ne retournera pas jusqu'à ce qu'il soit terminé. Dans votre exemple tel qu'il est maintenant, BeginInvoke enverra la requête pour exécuter votre délégué, et retournera tout de suite. Donc, il n'y a rien à retourner.

+0

Il peut être Invoke ou BeginInvoke tant que je récupère la valeur. Tout ce dont j'ai besoin est de lire la valeur de combobox ou de textbox d'un autre thread. – MadBoy

1

Est-ce que quelque chose comme ça que vous vouliez?

// begin execution asynchronously 
IAsyncResult result = myObject.BeginInvoke("data.dat", null, null); 

// wait for it to complete 
while (result.IsCompleted == false) { 
    // do some work 
    Thread.Sleep(10); 
    } 

// get the return value 
int returnValue = myObject.EndInvoke(result); 
+0

Pas tout à fait. Je suppose que l'utilisation de BeginInvoke n'est pas nécessaire parce que je veux juste lire la valeur de ComboBox ou TextBox et que cette valeur est importante pour exécuter d'autres commandes. Donc je pourrais l'utiliser dans Invoke. Je ne sais pas comment je pourrais utiliser votre exemple dans mon cas où le but principal est d'appeler la méthode d'un autre thread, lire la valeur gui et revenir à moi pour que le programme puisse aller plus loin. – 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

Ressemble à la solution de nobugz mais son air plus propre à moi :-) – MadBoy

+0

Oui, je suis d'accord. Quand j'ai posté ma solution, je ne vois pas encore la solution nobugz :) –

16

EndInvoke peut être utilisé pour obtenir une valeur de retour d'un appel BeginInvoke. Par exemple:

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

Dans l'ensemble un bon exemple, bien que dans mon cas, la solution nobugz est parfaite et exactement ce qui était nécessaire. – MadBoy

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

// simple, & élégante, mais il est nécessaire d'attendre un autre thread d'exécution délégué; Cependant, si vous ne pouvez pas continuer sans les résultats ...

Questions connexes