¿Cómo usar la barra de progreso de WinForms?

Quiero mostrar el progreso de los cálculos, que se realizan en una biblioteca externa.

Por ejemplo, si tengo algún método de cálculo, y quiero usarlo para 100000 valores en mi clase de Formulario, puedo escribir:

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Caluculate(int i) { double pow = Math.Pow(i, i); } private void button1_Click(object sender, EventArgs e) { progressBar1.Maximum = 100000; progressBar1.Step = 1; for(int j = 0; j < 100000; j++) { Caluculate(j); progressBar1.PerformStep(); } } } 

Debería realizar un paso después de cada cálculo. Pero, ¿qué ocurre si realizo todos los 100000 cálculos en un método externo? ¿Cuándo debería “realizar el paso” si no deseo que este método sea dependiente de la barra de progreso? Puedo, por ejemplo, escribir

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void CaluculateAll(System.Windows.Forms.ProgressBar progressBar) { progressBar.Maximum = 100000; progressBar.Step = 1; for(int j = 0; j < 100000; j++) { double pow = Math.Pow(j, j); //Calculation progressBar.PerformStep(); } } private void button1_Click(object sender, EventArgs e) { CaluculateAll(progressBar1); } } 

pero no quiero hacer eso.

Sugeriría que echen un vistazo a BackgroundWorker . Si tiene un bucle tan grande en su WinForm, se bloqueará y su aplicación parecerá que se ha colgado.

Mire BackgroundWorker.ReportProgress() para ver cómo informar el progreso al hilo de la interfaz de usuario.

Por ejemplo:

 private void Calculate(int i) { double pow = Math.Pow(i, i); } private void button1_Click(object sender, EventArgs e) { progressBar1.Maximum = 100; progressBar1.Step = 1; progressBar1.Value = 0; backgroundWorker.RunWorkerAsync(); } private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { var backgroundWorker = sender as BackgroundWorker; for (int j = 0; j < 100000; j++) { Calculate(j); backgroundWorker.ReportProgress((j * 100) / 100000); } } private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { progressBar1.Value = e.ProgressPercentage; } private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { // TODO: do something with final calculation. } 

Desde .NET 4.5, puede usar la combinación de asincronización y esperar con Progress para enviar actualizaciones al hilo de la interfaz de usuario:

 private void Calculate(int i) { double pow = Math.Pow(i, i); } public void DoWork(IProgress progress) { // This method is executed in the context of // another thread (different than the main UI thread), // so use only thread-safe code for (int j = 0; j < 100000; j++) { Calculate(j); // Use progress to notify UI thread that progress has // changed if (progress != null) progress.Report((j + 1) * 100 / 100000); } } private async void button1_Click(object sender, EventArgs e) { progressBar1.Maximum = 100; progressBar1.Step = 1; var progress = new Progress(v => { // This lambda is executed in context of UI thread, // so it can safely update form controls progressBar1.Value = v; }); // Run operation in another thread await Task.Run(() => DoWork(progress)); // TODO: Do something after all calculations } 

Actualmente, las tareas son la forma preferida de implementar lo que hace BackgroundWorker .

Las tareas y el Progress se explican con más detalle aquí:

  • Async en 4.5: Habilitar el progreso y la cancelación en las API Async
  • Informar el progreso de las tareas de Async por Stephen Cleary
  • Tarea de reemplazo de biblioteca paralela para BackgroundWorker?

Hola, hay un útil tutorial sobre las perlas de Dot Net: http://www.dotnetperls.com/progressbar

De acuerdo con Peter, necesita usar alguna cantidad de subprocesos o el progtwig simplemente se bloqueará, algo que frustra el propósito.

Ejemplo que usa ProgressBar y BackgroundWorker: C #

 using System.ComponentModel; using System.Threading; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, System.EventArgs e) { // Start the BackgroundWorker. backgroundWorker1.RunWorkerAsync(); } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { for (int i = 1; i <= 100; i++) { // Wait 100 milliseconds. Thread.Sleep(100); // Report progress. backgroundWorker1.ReportProgress(i); } } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Change the value of the ProgressBar to the BackgroundWorker progress. progressBar1.Value = e.ProgressPercentage; // Set the text. this.Text = e.ProgressPercentage.ToString(); } } } //closing here