c# - visual - ¿Cómo usar la barra de progreso de WinForms?
progressbar mientras se ejecuta un proceso c# (3)
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<int> 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<int>(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í:
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.
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 programa 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
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.
}