2009-11-08 15 views
5

Estoy escribiendo una interfaz de usuario de datos simple utilizando el enlace de datos .Net estándar a un conjunto de datos tipeados de SQL Server.Ejecutar un cuadro de diálogo modal en un hilo que no sea UI

Tengo un botón de recarga que llama al Fill en todos los DataAdapters para obtener nuevos datos de la base de datos (en caso de que otro usuario haya cambiado los datos).

Esto lleva un tiempo, durante el cual la IU está congelada. Se debe ejecutar en el subproceso UI o los controladores de eventos de enlace de datos lanzan excepciones de hilos cruzados.

Me gustaría mostrar un diálogo modal "Espere" en un hilo de fondo (para que pueda ser animado) mientras el hilo de la interfaz de usuario se conecta a la base de datos.

¿Cómo puedo mostrar un cuadro de diálogo modal en el subproceso no relacionado con la interfaz de usuario?


EDIT: Soy consciente de que la mejor práctica es ejecutar la operación en segundo plano, pero no puede hacerlo debido a los acontecimientos de enlace de datos.

Respuesta

8

Debería hacer lo contrario. Ejecute su proceso de larga duración en un hilo de fondo y deje el hilo de la IU libre para responder a las acciones del usuario.

Si desea bloquear cualquier acción del usuario mientras se procesa, tiene varias opciones, incluidos los cuadros de diálogo modales. Una vez que el subproceso de fondo se completa el procesamiento se puede informar al hilo principal sobre el resultado

+0

Como expliqué en la pregunta, no puedo. Soy muy consciente de que esta es la mejor práctica. – SLaks

+0

Creo que todavía puedes. Simplemente significa que el hilo de fondo no debe actualizar los datos directamente. Recuperarlos, empaquetarlos y delegarlos en el hilo principal para actualizar la interfaz de usuario – mfeingold

+0

Entiendo su dilema, pero sigo pensando que lo que estoy sugiriendo es mejor (menos problemas) que la alternativa – mfeingold

0
using(var frmDialog = new MyPleasWaitDialog()) { 
    // data loading is started after the form is shown 
    frmDialog.Load += (_sender, _e) { 
     // load data in separate thread 
     ThreadPool.QueueWorkItem((_state)=> { 
      myAdapter.Fill(myDataSet); 
      // refresh UI components in correct (UI) thread 
      frmDialog.Invoke((Action)myDataControl.Refresh); 
      // close dialog 
      frmDialog.Invoke((Action)frmDialog.Close()); 
     } 
    } 

    // shows dialog 
    frmDialog.ShowDialog(this); 
} 
+0

Necesita cargar datos en diferentes DataSet, que no está vinculado a la cuadrícula de datos, y luego volver a enlazar la cuadrícula de datos con el nuevo conjunto de datos. Y/o intente utilizar "BeginLoadData()" y "EndLoadData" en el conjunto de datos/datatable. – TcKs

+1

Como traté de explicar en la pregunta, 'myAdapter.Fill' arroja una InvalidOperationException en los manejadores de eventos de enlace de datos de la grilla cuando se llama en una cadena de fondo. Llamar a 'BeginLoadData' en la tabla no ayuda. – SLaks

+1

Por lo tanto, debe completar el otro conjunto de datos y luego volver a vincular la cuadrícula de datos a la instancia del conjunto de datos "nuevo" (lleno). – TcKs

2

El código que se ejecuta en el enlace de datos de eventos deben ser desacoplado de la interfaz de usuario, probablemente utilizando algún tipo de objeto de transferencia de datos.

Luego puede ejecutar la operación de consulta en un hilo separado o BackgroundWorker, y dejar el hilo de la interfaz de usuario tal como estaba.

Editar: La verdad forma rápida de solucionar este problema es conseguir que los eventos se ejecute en su propio delegado utilizando InvokeRequired y .Invoke. Eso dará el contexto de interfaz de usuario de métodos. Mi compañero de trabajo hace esto como si estuviera pasando de moda y me molesta muchísimo porque rara vez es una buena idea hacerlo de esta manera ... pero si quieres una solución rápida, esto funcionará. (No estoy en el trabajo, así que no tengo una muestra conmigo; intentaré encontrar algo.)

Editar 2: No estoy seguro de que lo que estás pidiendo sea posible. Hice una aplicación de muestra que creó un diálogo modal en otro hilo, y termina siendo no modal. En lugar de usar un diálogo modal, ¿podría usar algún otro control o conjunto de controles para indicar el cambio de progreso, probablemente directamente en la misma forma?

+0

¿Hay alguna manera simple de hacer esto y aún usar enlace de datos estándar con eventos de actualización? Estoy tratando de terminar este proyecto rápidamente. – SLaks

+0

Re. Editar: No puedo poner llamadas 'Invoke' dentro de DataGrid. – SLaks

+0

Re: Editar 2: Es posible que tengas razón. Si fuera una pregunta simple, no la habría pedido aquí. En cuanto a poner controles en el formulario, es aún peor, es completamente imposible tener algunos controles en un formulario propiedad de un hilo diferente. – SLaks

0

Aquí es un ejemplo del uso BackgroundWorker hacer la carga de datos y ejecutar una forma fácil de usar para mostrar 'registros de carga' o similares ...

public void Run() 
    { 
     bgWorkrFillDS = new BackgroundWorker(); 
     bgWorkrFillDS.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkrFillDS_RunWorkerCompleted); 
     bgWorkrFillDS.DoWork += new DoWorkEventHandler(bgWorkrFillDS_DoWork); 
     bgWorkrFillDS.RunWorkerAsync(); 
    } 

    void bgWorkrFillDS_DoWork(object sender, DoWorkEventArgs e) 
    { 
     BackgroundWorker bgWrkrFillDS = (BackgroundWorker)sender as BackgroundWorker; 
     if (bgWrkrFillDS != null) 
     { 
      // Load up the form that shows a 'Loading....' 
      // Here we fill in the DS 
      // someDataSetAdapter.Fill(myDataSet); 
     } 
    } 


    void bgWorkrFillDS_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     // Hide or unload the form when the work is done 
    } 

Espero que esto ayude ... Cuida , Tom.

+1

Lea la pregunta. Llamar a 'someDataSetAdapter.Fill' en el hilo de fondo lanzará una InvalidOperationException. – SLaks

0

He resuelto este problema creando un nuevo DataSet, cargándolo en segundo plano y llamando al DataSet.Merge en el hilo de la interfaz de usuario. Gracias a todos por su consejo, lo que condujo a esta solución.

Como un beneficio adicional, esto va mucho más rápido de lo que solía (llamando Fill en el fondo, que sólo funcionaba sin rejillas abiertas). ¿Alguien sabe por qué?

Cuestiones relacionadas