2009-08-01 12 views
18

de larga duración que tengo una aplicación Windows Forms en el que tengo que utilizar un bucle que tiene un gran número de llamadas remotas alrededor de 2000 - 3000 llamadas,WinForm aplicación se bloquea la interfaz de usuario durante la Operación

y durante la ejecución de la de loop, pierdo mi control en los controles de formulario y formulario, ya que se convierte en un proceso grande y en algún momento muestra "No responde", pero si espero durante un tiempo vuelve a aparecer, creo que necesito usar algún modelo de subprocesamiento para ese , ¿hay alguna idea, cómo puedo proceder para resolver el problema?

+0

Pon 'Application.DoEvents()' en el bucle. – i486

Respuesta

43

Debe realizar la operación de larga ejecución en una cadena de fondo.

Existen varias formas de hacerlo.

  1. Puede poner en cola la llamada al método para su ejecución en un hilo grupo de subprocesos (Ver here):

    ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod)); 
    

    En .NET 4.0 se puede utilizar el TaskFactory:

    Task.Factory.StartNew(() => YourMethod()); 
    

    Y en .NET 4.5 y posterior, puede (y debería, en lugar de TaskFactory.StartNew()) usar Task.Run():

    Task.Run(() => YourMethod()); 
    
  2. Puede usar BackgroundWorker para tener más control sobre el método si necesita cosas como actualizaciones de progreso o notificaciones cuando haya terminado. Arrastre el control a BackgroundWorker en su formulario y adjunte su método al evento dowork. Luego, simplemente inicie al trabajador cuando desee ejecutar su método. Por supuesto, puede crear el BackgroundWorker manualmente desde el código, solo recuerde que debe deshacerse de él cuando haya terminado.

  3. Cree un hilo totalmente nuevo para que su trabajo suceda. Este es el más complejo y no es necesario a menos que necesite un control realmente detallado sobre el hilo. Consulte la página de MSDN en la clase Thread si desea obtener más información al respecto.

Recuerde que con cualquier cosa roscada, que la actualización no se puede la interfaz gráfica de usuario o cambiar cualquier controles GUI desde un subproceso en segundo plano. Si desea hacer algo en la GUI, debe usar Invoke (y InvokeRequired) para volver a activar el método en la secuencia de la GUI. Ver here.

+1

Creo que esto me ayudará, ¡probaré BackGroundWorker! – shahjapan

+0

'BackgroundWorker' parecía hacer el truco para mí! –

2

Obviamente, necesita utilizar hilos de fondo. Le sugiero que lea this free e-book.

2

No es necesario hilo. Utilice Application.DoEvents(); //repaint or respond to msg Por ejemplo:

foreach (DirectoryInfo subDir in dirInfo.EnumerateDirectories()) 
{ 
    count = count + 1; 
    listBoxControl4.Items.Add(count.ToString() + ":" + subDir.FullName); 
    Application.DoEvents(); //allow repaint to see status 
    ProduceListing(subDir, " "); 
} 

Esto irá a través de todas las carpetas de forma recursiva y escribir los nombres en un cuadro de lista. Esto puede llevar mucho tiempo. Con DoEvents(), mostrará el progreso en cada ciclo. Básicamente, la llamada permite que Windows en este hilo actualice cualquier cosa en el bucle de msg de Windows. Asegúrese de ver la recursión involuntaria, ya que cualquier control en el formulario se volverá a hacer clic aunque el primero no se haya completado. Esto funciona bien (Es una copia de la antigua llamada Delphi Application.ProcessMessages(). Puede buscar eso para ver por qué funciona y qué buscar.

+4

Llamar a 'DoEvents' es algo malo. Puede causar todo tipo de problemas de enhebrado, como la reentrada. Debería evitarse por completo. – Enigmativity

+0

-1 Exactamente lo que estaba buscando. Pero por una razón exactamente opuesta. Quiero ejecutar algo en segundo plano, y pausar la interfaz de usuario en un bucle para que el siguiente paso no suceda hasta que el trabajador de segundo plano finalice. El evento Finalizado de BackgroundWorker me permite establecer un booleano. La interfaz de usuario hace while (! [That boolean]) {Application.DoEvents(); Dormir (50);}. – TamusJRoyce

+0

+1 Me encanta usar Application.DoEvents() para aplicaciones simples que construyo para mí, es más rápido de codificar. Me parece bien usarlo siempre que sepa que procesa todos los eventos que pueden interrumpir su ciclo, como cerrar el formulario. Normalmente desactivo el botón una vez que se hace clic, y desactivo el cierre del formulario mientras se está ejecutando. – Aximili

4
private voidForm_Load(object sender, EventArgs e) 
    { 
     MethodInvoker mk = delegate 
     { 
      //your job 
     }; 
     mk.BeginInvoke(callbackfunction, null); 
    } 

    private void callbackfunction(IAsyncResult res) 
    { 
     // it will be called when your job finishes. 
    } 

use MethodInvoker es la forma más fácil.

Cuestiones relacionadas