2010-02-06 6 views
31

Tengo este pequeño método que se supone que es seguro para subprocesos. Todo funciona hasta que quiero que tenga valor de retorno en lugar de vacío. ¿Cómo obtengo el valor de retorno cuando se llama a BeginInvoke?Cómo obtener el valor de retorno cuando se invoca BeginInvoke/Invoke en C#

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

    } 

Editar: Supongo que tener BeginInvoke no es nessecary en este caso, ya que necesito valor de interfaz gráfica de usuario antes de que el hilo puede continuar. Entonces, usar Invoke también es bueno. Simplemente no tengo idea de cómo usarlo en el siguiente ejemplo para devolver el valor.

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

    } 

pero no está seguro cómo conseguir valor con que el código sea;)

+0

Si necesita trabajar con el valor devuelto por una invocación, debe ser porque necesita un patrón de "estilo de continuación de continuación". Que se puede aliviar con 'async',' await' y 'Task'. –

Respuesta

49

Tienes que invocar() para que puedas esperar a que la función regrese y obtengas su valor de retorno. También necesitarás otro tipo de delegado. Esto se debe trabajar;

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 desea un valor de retorno de usted método, no debe utilizar la versión asíncrona del método, se debe utilizar .Invoke(...) . Que es sincrónico, es decir ejecutará su delegado y no volverá hasta que esté completo. En su ejemplo como está ahora, BeginInvoke enviará la solicitud para ejecutar a su delegado, y regresará de inmediato. Entonces no hay nada a lo que regresar.

+0

Puede ser Invoke o BeginInvoke siempre que recupere el valor. Todo lo que necesito es leer el valor del cuadro combinado o el cuadro de texto de otro hilo. – MadBoy

1

¿Es algo así como lo que quería?

// 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

No del todo. Supongo que el uso de BeginInvoke no es nessecary ya que solo quiero leer el valor de ComboBox o TextBox y ese valor es importante para ejecutar otros comandos. Entonces podría usarlo en Invoke. Simplemente no estoy seguro de cómo podría usar su ejemplo en mi caso, donde el propósito principal es llamar al método desde otro hilo, leer el valor de la interfaz gráfica de usuario y volver a verme para que el programa pueda ir más allá. – 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

Se parece a la solución nobugz pero su apariencia es más clara para mí :-) – MadBoy

+0

Sí, estoy de acuerdo. Cuando publiqué mi solución, todavía no veo la solución nobugz :) –

16

EndInvoke se puede utilizar para obtener un valor de retorno de una llamada BeginInvoke. Por ejemplo:

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

Buen ejemplo en general, aunque en mi caso la solución de nobugz es perfecta y es exactamente lo que se requería. – MadBoy

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

// sencilla & elegante pero es necesario esperar a que otro hilo para ejecutar delegado; sin embargo, si no puede continuar sin los resultados ...

Cuestiones relacionadas