How to use WinForms progress bar?
Since .NET 4.5 you can use combination of async and await with Progress for sending updates to UI thread:
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
}
Tasks are currently the preferred way to implement what BackgroundWorker
does.
Tasks and
Progress
are explained in more detail here:
- Async in 4.5: Enabling Progress and Cancellation in Async APIs
- Reporting Progress from Async Tasks by Stephen Cleary
- Task parallel library replacement for BackgroundWorker?
I would suggest you have a look at BackgroundWorker. If you have a loop that large in your WinForm it will block and your app will look like it has hanged.
Look at BackgroundWorker.ReportProgress()
to see how to report progress back to the UI thread.
For example:
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.
}