2009-09-24 80 views
15

我有這樣的問題:C#Winform ProgressBar和BackgroundWorker

我有一個名爲MainForm的窗體。我在這張表格上進行了長時間的操作。

當這個長時間的操作正在進行時,我需要在MainForm的頂部顯示另一個名爲ProgressForm。

ProgressForm包含一個進度條。長期操作發生時需要更新哪些內容。

Long操作完成後,ProgressForm應該自動關閉。

我已經寫了一些類似於下面的代碼:

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace ClassLibrary 
{ 
    public class MyClass 
    { 
     public static string LongOperation() 
     { 
      Thread.Sleep(new TimeSpan(0,0,30)); 

      return "HelloWorld"; 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class ProgressForm : Form 
    { 
     public ProgressForm() 
     { 
      InitializeComponent(); 
     } 

     public ProgressBar ProgressBar 
     { 
      get { return this.progressBar1; } 
      set { this.progressBar1 = value; } 
     } 
    } 
} 

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 

using ClassLibrary; 

namespace BackgroungWorker__HelloWorld 
{ 
    public partial class MainForm : Form 
    { 
     ProgressForm f = new ProgressForm(); 

     public MainForm() 
     { 
      InitializeComponent(); 
     } 

     int count = 0; 
     private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
     { 
      if (f != null) 
      { 
       f.ProgressBar.Value = e.ProgressPercentage; 
      } 

      ++count; 
     } 

     private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if (e.Cancelled) 
      { 
       MessageBox.Show("The task has been cancelled"); 
      } 
      else if (e.Error != null) 
      {     
       MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString()); 
      } 
      else 
      { 
       MessageBox.Show("The task has been completed. Results: " + e.Result.ToString()); 
      } 
     } 


     private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (f == null) 
      { 
       f = new ProgressForm(); 
      } 

      f.ShowDialog(); 

      //backgroundWorker1.ReportProgress(100); 

      MyClass.LongOperation(); 

      f.Close(); 
     } 

     private void btnStart_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.RunWorkerAsync(); 
     } 

     private void btnCancel_Click(object sender, EventArgs e) 
     { 
      backgroundWorker1.CancelAsync(); 

      this.Close(); 
     } 
    } 
} 

我沒有找到更新進度條的方式。

我應該在哪裏放置backgroundWorker1.ReportProgress(),我應該怎麼稱呼它?

我不能在MyClass中做任何改變。 Coz,我不知道會發生什麼,或者需要多長時間才能完成我的應用程序的這一層操作。

任何人都可以幫助我嗎?

回答

12

一個問題是你睡了30秒。通常情況下,您可以在長時間運行的任務中的不同位置撥打ReportProgress。因此爲了證明這一點,您可能需要將代碼更改爲睡眠1秒,但需要30次 - 每次完成睡眠時調用ReportProgress

另一個問題是,你正在顯示你的ProgressForm後臺線程。您應該在線程中啓動它,但將後臺工作人員的ProgressChanged事件掛接到該線程。然後,當後臺工作人員報告進度時,進度表將被更新。

+0

我不能在MyClass中做任何改變。因爲,我不知道我的應用程序的這一層會發生什麼。 – anonymous 2009-09-24 10:58:59

+6

然後你不能準確地報告進度。我的意思是你可以在ProgressForm中添加一個定時器來每秒增加進度條,但這隻會提供一個幻覺。如果你無法找到真正的進度,那麼進度條有多有用? – 2009-09-24 11:00:45

2

ReportProgress是您必須在「工作」方法中調用的方法。 此方法將引發'ProgressChanged'事件。

在您的表單中,您可以將事件處理程序附加到ProgressChanged事件。在事件處理程序中,您可以更改進度條的位置。 您還可以將事件處理程序附加到RunWorkerCompleted事件,並且在該事件處理程序中,可以關閉包含進度條的表單。

+0

這是我猜的一般解決方案。 Plz再次閱讀問題。 – anonymous 2009-09-24 11:09:10

2

應當注意你需要設置

backgroundWorker1.WorkerReportsProgress = true; 

,如果你想在後臺工作,以提高ProgressChanged事件和

backgroundWorker1.WorkerSupportsCancellation = true; 
如果你希望能夠取消工作線程

正如其他人所說的,在UI線程中運行f.ShowDialog()並使用ProgressChanged更新ProgressWindow。

要讓ProgressForm自行關閉,請在backgroundWorker1_RunWorkerCompleted中調用f。關();這意味着長時間的操作已經完成,我們可以關閉窗口。

+0

從UI線程調用ProgressWindow有什麼好處? – anonymous 2009-09-24 11:17:58

0

這裏需要的是不要將整個主表單傳遞給類,而只需將BackgroundWorker的實例!你需要投發件人爲背景的工人,像這樣:

private void bgWorker_DoWork(object sender DoWorkEventArgs e) 
{ 
    // Get the BackgroundWorker that raised this event 
    BackgroundWorker worker = sender as BackgroundWorker; 

    // And now you just send worker to whatever class you need like so: 
    bgArgs args = e.Argument as bgArgs; 
    MyClass objMyClass = new MyClass(); 

    MyClass.MyMethod(strValue, args.Option, worker); 

    // Do something based on return value. 
} 

,然後在MyClass.MyMethod()你會做的進度計算,簡單地提高worker.ReportProgress(int percentage)事件來更新您的主UI窗體上的進度條或諸如此類的東西!

這應該完美!

查看本文的MSDN文章以獲取更多詳細信息,請參閱他們的斐波那契示例,這是他們所做的工作,因爲CalculateFibonacci是向主窗體的UI發送更新的自定義類。

有關更多詳細信息,請參閱MSDN BackgroundWorker Class