2009-07-01 15 views
12

En mi programa [C# + winforms]. Tengo la barra de progreso & listview.Winforms Barra de progreso no se actualiza (C#)

A través de un método realizo algunas operaciones & y luego actualizo los datos en Listview. El número de registros agregados es el valor que estoy configurando para la propiedad ProgressBar.value. Lo que quiero aquí es, de acuerdo con el valor de la barra de progreso, debe mostrar su progreso. Sin embargo, la barra de progreso no se está actualizando. Solo al final de la ejecución del método, la barra de progreso muestra el progreso completo, es decir, 100%

¿Alguien puede ayudarme a este respecto?

Gracias, Amit

+2

no sé lo suficiente sobre C# aquí para responder, pero en Java Swing it necesita tener un hilo separado o de lo contrario obtendrá este mismo comportamiento. – Chet

Respuesta

26

Suena como usted está bloqueando el hilo de interfaz de usuario - es decir, no se ha lanzado el sistema de hacer cualquier pintura.

Una respuesta hacky es inyectar Application.DoEvents() en su código, pero esto es arriesgado y tiene problemas con la reincorporación, etc .; y es un poco hacky.

Una mejor opción puede ser para hacer el procesamiento en un BackgroundWorker, cambiando periódicamente al hilo de interfaz de usuario para actualizar las cosas (Control.Invoke) - pero esto puede ser difícil si va a añadir un montón de artículos a un ListView.

Ejemplo completo (aunque es posible que desee por lotes los cambios de interfaz de usuario - no es una fila a la vez):

using System; 
using System.ComponentModel; 
using System.Threading; 
using System.Windows.Forms; 

class MyForm : Form 
{ 
    BackgroundWorker worker; 
    ListView list; 
    Button btn; 
    ProgressBar bar; 
    public MyForm() 
    { 
     Text = "Loader"; 
     worker = new BackgroundWorker(); 
     worker.WorkerReportsProgress = true; 
     worker.ProgressChanged += worker_ProgressChanged; 
     worker.DoWork += worker_DoWork; 
     worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
     list = new ListView(); 
     list.Dock = DockStyle.Fill; 
     Controls.Add(list); 
     btn = new Button(); 
     btn.Text = "Load"; 
     btn.Dock = DockStyle.Bottom; 
     Controls.Add(btn); 
     btn.Click += btn_Click; 
     bar = new ProgressBar(); 
     bar.Dock = DockStyle.Top; 
     Controls.Add(bar); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     btn.Enabled = true; 
    } 

    void btn_Click(object sender, EventArgs e) 
    { 
     worker.RunWorkerAsync(); 
     btn.Enabled = false; 
    } 


    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     for (int i = 0; i < 100; i++) 
     { 
      string newRow = "Row " + i.ToString(); 
      worker.ReportProgress(i, newRow); 
      Thread.Sleep(100); 
     } 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     list.Items.Add((string)e.UserState); 
     bar.Value = e.ProgressPercentage; 
    } 

    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.Run(new MyForm()); 
    } 
} 
0

El ProgressBar.Value debe estar entre 0 y 100.

Mi conjetura es que su problema es que está actualizando ListView en el hilo de la GUI. Eso significa que deberá llamar al Application.DoEvents() después de cambiar la propiedad ProgressBar.Value.

Lo mejor sería ejecutar en un BackgroundWorker y utilizar el evento ProgressChanged para manejar la actualización ProgressBar.

Here's another question sobre el mismo tema.

+0

¿Por qué el valor de la barra de progreso debe estar entre 0 y 100? – Hemant

+0

No hay otra razón que la conveniencia cuando se trata de porcentajes ... –

+0

Puede aumentar la barra de progreso max estableciendo progressBar1.Maximum = [int], donde [int] es un entero. –

3

Como dijo Marc, debe asegurarse de hacer girar un nuevo hilo para hacer su cálculo de larga ejecución. De esta manera, el hilo de la interfaz de usuario (que es el que tiene que hacer todas las actualizaciones de la pantalla) puede volver a dibujar la barra de progreso cada vez que cambie el porcentaje completado.

Es importante tener en cuenta que solo el subproceso de interfaz de usuario puede actualizar la interfaz. Entonces, una vez que está ejecutando un hilo separado, debe pasar por un aro adicional para asegurarse de que su cambio de UI se procese en el hilo de la interfaz de usuario. Si no está seguro de qué hilo se está ejecutando, puede verificar el valor de InvokeRequired (si su clase es System.Windows.Form) para ver si está realmente en el hilo de la interfaz de usuario.

Para obtener su comando procesado en el hilo de la interfaz de usuario, use la función Control.Invoke() para asegurarse de que la actualización se procesa en el subproceso de interfaz de usuario para el control con el que está trabajando.

En mi código de ejemplo a continuación, estoy creando un tipo de función de delegado y declarando la función invocada por adelantado .... No lo he hecho con ninguna de las funciones C# 3.5, pero apuesto a que podría funcionar una expresión lamba para hacer lo mismo.

private void bCreateInvoices_Click(object sender, EventArgs e) 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(CreateInvoices); 
     worker.RunWorkerAsync(this); 
    } 

// Here is the long running function that needs to update the progress bar 
public void CreateInvoices(object sernder, DoWorkEventArgs e) 
    { 
     int totalChecked = CountCheckedServiceOrders(); 
     int totalCompleted = 0; 

     foreach (...data to process...) { 
      totalCompleted++; 
      if (InvokeRequired) { 
       Invoke(new Change(OnChange), "status text", 
         totalCompleted, totalChecked);     
      } 
     } 
    } 

    // this code updates the status while a background thread works 
    private delegate void Change(string status, int complete, int total); 
    private void OnChange(string status, int complete, int total) 
    { 
     if (status == null) { 
      progressBar.Visible = false; 
      lStatus.Text = "Task complete"; 
      progressBar.Value = 0; 
     } else { 
      progressBar.Visible = true; 
      progressBar.Minimum = 0; 
      progressBar.Maximum = total; 
      progressBar.Value = complete; 
      lStatus.Text = status; 
     } 

    } 

Tome un vistazo a la MSDN Control.InvokeRequired manual page y la MSDN Control.Invoke manual page de algo más de información.

Amigos
4

realmente lo siento,

En realidad, estaba assiging valor al campo ProgressBar.value pero no usamos método de actualización(). Utilicé ese & mi problema se resolvió.

Gracias a todos por sus respuestas

Cuestiones relacionadas