如何使用WinForms进度条?

我想显示在外部库中执行的计算的进度。

例如,如果我有一些计算方法,我想在我的Form类中使用它100000的值,我可以写:

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(); } } } 

每次计算后我应该执行一步。 但是如果我用外部方法进行所有100000次计算呢? 我应该什么时候“执行步骤”,如果我不想让这个方法依赖于进度条? 我可以,例如,写

 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); } } 

但我不想这样做。

我build议你看看BackgroundWorker 。 如果你的WinForm中有一个很大的循环,它将被阻塞,你的应用程序看起来就像被挂起了一样。

查看BackgroundWorker.ReportProgress()来查看如何将进度报告回UI线程。

例如:

 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. } 

从.NET 4.5开始,您可以使用asynchronous组合并等待 进度 ,将更新发送到UI线程:

 private void Caluculate(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++) { Caluculate(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 } 

目前,任务是实现BackgroundWorker的首选方式。

任务和Progress在这里更详细地解释:

  • 4.5中的asynchronous:在asynchronousAPI中启用进度和取消
  • 从 Stephen Cleary 报告asynchronous任务的进度
  • 任务并行库replace为BackgroundWorker?

嘿,有一个有用的教程DotNet珍珠: http : //www.dotnetperls.com/progressbar

与彼得一致,你需要使用一定数量的线程,否则程序就会挂起,有些打败目的。

使用ProgressBar和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