2009-09-24 22 views
15

Tengo un problema como este:C# Winform ProgressBar y BackgroundWorker

Tengo un Formulario llamado MainForm. Tengo una operación larga que se llevará a cabo en este formulario.

Mientras se realiza esta operación larga, necesito mostrar otra de ProgressForm con nombre en la parte superior de MainForm.

ProgressForm contiene una barra de progreso. Que necesita actualizarse mientras se lleva a cabo la operación larga.

Una vez completada la operación larga, ProgressForm debe cerrarse automáticamente.

he escrito algo de código como el siguiente:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace ClassLibrary 
{ 
    public class MyClass 
    { 
     public static string LongOperation() 
     { 
      Thread.Sleep(new TimeSpan(0,0,30)); 

      return "HelloWorld"; 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class ProgressForm : Form 
    { 
     public ProgressForm() 
     { 
      InitializeComponent(); 
     } 

     public ProgressBar ProgressBar 
     { 
      get { return this.progressBar1; } 
      set { this.progressBar1 = value; } 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

using ClassLibrary; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class MainForm : Form 
    { 
     ProgressForm f = new ProgressForm(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     int count = 0; 
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      if (f != null) 
      { 
       f.ProgressBar.Value = e.ProgressPercentage; 
      } 

      ++count; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       MessageBox.Show("The task has been cancelled"); 
      } 
      else if (e.Error != null) 
      {     
       MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString()); 
      } 
      else 
      { 
       MessageBox.Show("The task has been completed. Results: " + e.Result.ToString()); 
      } 
     } 


     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (f == null) 
      { 
       f = new ProgressForm(); 
      } 

      f.ShowDialog(); 

      //backgroundWorker1.ReportProgress(100); 

      MyClass.LongOperation(); 

      f.Close(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.CancelAsync(); 

      this.Close(); 
     } 
    } 
} 

yo no estoy encontrando la manera de actualizar el progressBar.

¿Dónde debo colocar backgroundWorker1.ReportProgress() y cómo debo llamar esto?

No debo hacer ningún cambio en MyClass. Coz, no sé qué pasaría o cuánto tiempo llevaría completar la operación en esta capa de mi aplicación.

¿Alguien me puede ayudar?

Respuesta

12

Un problema es que duerme durante 30 segundos. Normalmente llamarías al ReportProgress en varios puntos dentro de tu tarea de larga ejecución. Entonces, para demostrar esto, es posible que desee cambiar su código para que duerma durante 1 segundo, pero 30 veces, llamando al ReportProgress cada vez que termine de dormir.

Otro problema es que está mostrando su ProgressFormde el hilo de fondo. Debe iniciarlo en el subproceso UI, pero enganche el evento ProgressChanged del trabajador de fondo. Luego, cuando el trabajador de base informe el progreso, se actualizará el formulario de progreso.

+0

No debo hacer ningún cambio en MyClass. Coz, no sé qué pasaría en esta capa de mi aplicación. – anonymous

+6

Entonces no puede informar el progreso con precisión. Quiero decir que puedes agregar un temporizador al 'ProgressForm' para simplemente incrementar la barra de progreso cada segundo, pero eso solo proporcionará una ilusión. Si no tiene forma de averiguar el progreso * real *, ¿qué tan útil es una barra de progreso? –

2

ReportProgress es el método que tendrá que llamar en su método de "trabajo". Este método generará el evento 'ProgressChanged'.

En su formulario, puede adjuntar un controlador de eventos al evento ProgressChanged. Dentro de ese manejador de eventos, puede cambiar la posición de la barra de progreso. También puede adjuntar un manejador de eventos al evento RunWorkerCompleted, y dentro de ese manejador de eventos, puede cerrar el formulario que contiene la barra de progreso.

+0

Esta es una solución general, supongo. Plz leyó el problema de nuevo. – anonymous

2

Debe tenerse en cuenta que necesita para establecer

backgroundWorker1.WorkerReportsProgress = true; 

si desea que el trabajador de fondo para elevar el caso ProgressChanged y

backgroundWorker1.WorkerSupportsCancellation = true; 

si desea ser capaz de cancelar el subproceso de trabajo.

Como han dicho los otros, ejecute f.ShowDialog() en el subproceso de la interfaz de usuario y use ProgressChanged para actualizar ProgressWindow.

Para obtener el ProgressForm para cerrar, en backgroundWorker1_RunWorkerCompleted, llame a f.Cerca(); Esto significa que la operación larga se ha completado y podemos cerrar la ventana.

+0

¿Cuál es la ventaja de llamar a ProgressWindow desde el hilo de la interfaz de usuario? – anonymous

0

Lo que se necesita aquí es no pasar todo el formulario principal a la clase, ¡sino simplemente la instancia de su BackgroundWorker! Es necesario para emitir el remitente como trabajador de Antecedentes de esta manera:

private void bgWorker_DoWork(object sender DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event 
    BackgroundWorker worker = sender as BackgroundWorker; 

    // And now you just send worker to whatever class you need like so: 
    bgArgs args = e.Argument as bgArgs; 
    MyClass objMyClass = new MyClass(); 

    MyClass.MyMethod(strValue, args.Option, worker); 

    // Do something based on return value. 
} 

Y luego, en su MyClass.MyMethod() que haría los cálculos de progreso y simplemente provocar el evento worker.ReportProgress(int percentage) para actualizar la barra de progreso o lo que sea en su forma principal interfaz de usuario!

¡Esto debería funcionar perfectamente!

revisar este artículo de MSDN para más detalles, véase el ejemplo de Fibonacci, que es lo que hacen desde CalculateFibonacci es una clase personalizada que envía cambios a la interfaz de usuario del formulario principal.

Consulte MSDN BackgroundWorker Class para obtener más información.