2008-09-19 19 views

Respuesta

14

El BackgroundWorker suena como el objeto que desea.

0

Application.DoEvents() o posiblemente ejecute el lote en un hilo separado?

+0

Usaría BackgroundWorker y haría que el lote se ejecutara en un hilo separado. No me gusta Application.DoEvents() porque incluso si está haciendo eso, mientras no está haciendo eso y está procesando el trabajo, su UI no deja de responder por completo y puede parecer "colgada" para su usuario. –

+2

No hagas esto, es un verdadero olor a código. Nunca he visto un 'Application.DoEvents()' en el código de producción donde pensé: "Esa fue la solución más fácil y más correcta". –

+0

Si usa CLR Profiler 2.0, notará que el uso de DoEvents creará MUCHOS controladores, ¡que se quedan! Sugeriría usar BackgroundWorker como dijo jolson. – joek1975

1

Utilice el componente backgroundworker para ejecutar el procesamiento por lotes en un subproceso separado, esto no afectará al subproceso de interfaz de usuario.

3

Ejecuta el largo proceso en una cadena de fondo. La clase de trabajador en segundo plano es una forma fácil de hacerlo: proporciona una compatibilidad sencilla para enviar actualizaciones de progreso y eventos de finalización para los que los manejadores de eventos son llamados en la secuencia correcta para usted. Esto mantiene el código limpio y conciso.

Para mostrar las actualizaciones, las barras de progreso o el texto de la barra de estado son dos de los enfoques más comunes.

La clave para recordar es que si usted está haciendo las cosas en un subproceso en segundo plano, debe cambiar al hilo de interfaz de usuario con el fin de actualizar los controles de ventanas, etc.

4

La forma más rápida y sucia está utilizando Application.DoEvents() pero esto puede causa problemas con el orden en que se manejan los eventos. Por lo tanto, no se recomienda

El problema probablemente no es que deba ceder al hilo de la interfaz de usuario sino que haga el procesamiento en el hilo de la interfaz de usuario impidiéndole manejar los mensajes. Puede utilizar el componente backgroundworker para realizar el procesamiento por lotes en un subproceso diferente sin bloquear el subproceso de interfaz de usuario.

0

DoEvents() era lo que estaba buscando pero también he votado las respuestas de Backgroundworker porque parece una buena solución que investigaré un poco más.

+1

Considere definitivamente el BackgroundWorker: cada vez que me encuentro con DoEvents(), nunca ha sido divertido solucionar problemas posteriores. –

1

Quiero repetir lo que mis comentaristas anteriores notaron: por favor evite DoEvents() siempre que sea posible, ya que esto es casi siempre una forma de "piratear" y causa pesadillas de mantenimiento.

Si va por la carretera BackgroundWorker (que sugiero), tendrá que ocuparse de las llamadas cruzadas a la IU si desea llamar a cualquier método o propiedad de los Controles, ya que estos son afines y deben ser ser llamado solo desde el hilo en el que fueron creados. Use Control.Invoke() y/o Control.BeginInvoke() según corresponda.

1

Si está ejecutando en un subproceso de fondo/trabajador, puede llamar Control.Invoke en uno de los controles de interfaz de usuario para ejecutar un delegado en el hilo de interfaz de usuario.

Control.Invoke es sincrónico (Espera hasta que el delegado regrese). Si no desea esperar, use .BeginInvoke() para solo poner en cola el comando.

El valor de retorno de .BeginInvoke() le permite verificar si el método se completó o esperar hasta que se complete.

3

Para aclarar lo que dice la gente sobre DoEvents, aquí hay una descripción de lo que puede suceder.

Digamos que tiene algún formulario con datos y su evento de larga ejecución lo está guardando en la base de datos o generando un informe basado en él. Comienza a guardar o generar el informe, y luego periódicamente llama a DoEvents para que la pantalla siga pintando.

Lamentablemente, la pantalla no solo está pintando, también reaccionará a las acciones del usuario. Esto se debe a que DoEvents detiene lo que está haciendo ahora para procesar todos los mensajes de Windows que esperan ser procesados ​​por su aplicación Winforms. Estos mensajes incluyen solicitudes para volver a dibujar, así como también cualquier usuario que escriba, haga clic en, etc.

Así, por ejemplo, mientras guarda los datos, el usuario puede hacer cosas como hacer que la aplicación muestre un cuadro de diálogo modal que es completamente no relacionado con la tarea de larga ejecución (por ejemplo, Ayuda-> Acerca de). Ahora está reaccionando a las nuevas acciones de usuario dentro de la tarea que ya se está ejecutando durante mucho tiempo. DoEvents volverá cuando todos los eventos que estaban esperando cuando lo llamó hayan finalizado, y luego su tarea de ejecución larga continuará.

¿Qué pasa si el usuario no cierra el cuadro de diálogo modal? Su tarea de ejecución prolongada espera por siempre hasta que este diálogo se cierre. Si se compromete con una base de datos y realiza una transacción, ahora mantiene abierta una transacción mientras el usuario toma un café. O bien, su transacción se agota y usted pierde su trabajo de persistencia, o la transacción no expira y potencialmente puede bloquear a otros usuarios del DB.

Lo que sucede aquí es que Application.DoEvents hace que su código vuelva a ingresar. Vea la definición de wikipedia here. Tenga en cuenta algunos puntos de la parte superior del artículo, que para el código que se reentrante, es:

  • No debe contener datos no constantes estáticos (o globales).
  • Debe funcionar solo en los datos que le proporciona la persona que llama.
  • No debe confiar en los bloqueos de los recursos singleton.
  • No debe llamar a programas o rutinas de computadora no reentrantes.

Es muy poco probable que el código de larga ejecución en una aplicación Windows Forms está trabajando únicamente en datos pasados ​​al método por el que llama, no es titular de los datos estáticos, no mantiene bloqueos, y pide solamente otros métodos de reentrada.

Como muchas personas están diciendo, DoEvents puede dar lugar a algunos escenarios muy extraños en el código. Los errores a los que puede conducir pueden ser muy difíciles de diagnosticar, y es probable que su usuario no le diga "Oh, esto podría haber sucedido porque hice clic en este botón no relacionado mientras esperaba que se guardara".

+1

wow, ¿cómo se volvió a activar esto? ¡Creo que debería leer las fechas de publicación antes de escribir largas respuestas! Aún así, podría ayudar a alguien ... –

+1

+1 para obtener buenos detalles. –

1
Uso Backgroundworker

, y si también está intentando actualizar el hilo GUI por el manejo de la ProgressChanged evento (como, por un ProgressBar), asegúrese de establecer también WorkerReportsProgress=true, o el hilo que está reportando el progreso va a morir la primera vez intenta llamar al ReportProgress ...

se emite una excepción, pero es posible que no la vea a menos que tenga activada la función 'when throwwn', y la salida solo mostrará que el hilo salió.

Cuestiones relacionadas