2012-03-08 18 views
5

Tengo una pequeña aplicación que necesita para probar las cadenas de conexión de SQL para una serie de conexiones (cada uno hecho de uno en uno). Para hacer esto, establezco el ConnectionTimeout = 5 temporalmente para evitar una larga espera si la conexión no es válida y ConnectionTimeout = 0 (espere para siempre), por ejemplo.TPL Cómo realizar una 'devolución de llamada'

Para evitar el ahorcamiento de interfaz de usuario mientras se intenta Open() una mala conexión (incluso con ConnectionTimeout = 5 la espera para la SqlException puede ser de hasta veinte segundos), quiero ejecutar la prueba en un hilo separado usando tarea paralela Biblioteca (TPL) Por lo tanto, spin-off de mi nuevo hilo como:

Task<bool> asyncTestConn = Task.Factory.StartNew<bool> 
    (() => TestConnection(conn, bShowErrMsg)); 
return asyncTestConn.Result; 

El problema es que esto todavía está bloqueando la interfaz de usuario (claramente), ya que está esperando el resultado antes de regresar a la persona que llama. ¿Cómo permito que el código devuelva el control a la IU (liberando la GUI) mientras obtengo el resultado final del Task asincrónico?

Además, desde dentro de un Task legítimamente puedo hacer MessageBox.Show("Some message")? Esto no funciona para BackgroundWorkers y este subproceso agrupado es un subproceso de fondo por defecto; sin embargo, no parece ser un problema. Gracias por tu tiempo.

Respuesta

4

Tiene usted razón, aquí es donde la espera sucede:

return asyncTestConn.Result; 

Simplemente podría construir el código de acabado en la cola de TestConnection() o utilizar un Continuación:

// untested 
//Task<bool> asyncTestConn = Task.Factory.Create<bool> (
Task<bool> asyncTestConn = new Task<bool> (
    () => TestConnection(conn, bShowErrMsg)); 
asyncTestConn.ContinueWith(MyFinishCode); 
asyncTestConn.Start() 

legítimamente puedo hacer MessageBox.Show("Some message")?

En realidad Sí, el MessageBox es seguro para subprocesos. Debería ser posible desde un Bgw también.

Pero está prolongando mucho la vida de la tarea, no es una buena idea.

+0

Muchas gracias por su respuesta. La idea es volver a pasar el control a la interfaz de usuario/GUI lo antes posible, ¿cómo/lo anterior puede lograrlo? Si estoy llamando al código anterior desde un método llamado 'ParrTestConn (conexión de SqlConnection, string bShowErrMsg)', entonces no puedo decir 'asyncTestConn.ContinueWith (ParrTestConn (conn, bShowErrMsg))' ... ¿O puedo? – MoonKnight

+0

@Killer Puede simplemente regresar después del Inicio(). La GUI debe seguir siendo receptiva al usar esto. –

+0

No tengo el método 'Task.Factory.Create ' avilible? – MoonKnight

5

Para el TPL, ContinueWith es exactamente lo que desea. Ampliando la respuesta de Henk:

var asyncTestConn = Task.Factory.StartNew(() => TestConnection(conn, bShowErrMsg)); 
// Henk's "MyFinishCode" takes a parameter representing the completed 
// or faulted connection-testing task. 
// Anything that depended on your "return asyncTestConn.Result;" statement 
// needs to move into the callback method. 
asyncTestConn.ContinueWith(task => 
    { 
     switch (task.Status) 
     { 
      // Handle any exceptions to prevent UnobservedTaskException. 
      case TaskStatus.Faulted: /* Error-handling logic */ break; 
      case TaskStatus.RanToCompletion: /* Use task.Result here */ break; 
     } 
    }, 
    // Using this TaskScheduler schedules the callback to run on the UI thread. 
    TaskScheduler.FromCurrentSynchronizationContext()); 
+0

Muy útil. Gracias. La combinación de las dos respuestas es absolutamente nueva. – MoonKnight

Cuestiones relacionadas