2012-07-13 62 views
0

我有一個簡單的表單,應該啓動一個計時器,執行耗時的操作,並在該操作正在工作時以特定間隔更新進度條。目前,耗時的操作必然會涉及到SearchButton。然而,沒有任何反應進度條,即使耗時的操作(在這種情況下下載),並需要幾秒鐘:如何設置ProgressBar以在每個計時器的滴答時間遞增?

public partial class Form1 : Form 
{ 
    System.Windows.Forms.Timer searchProgressTimer; 

    public Form1() 
    { 
     InitializeComponent(); 
     this.searchProgressTimer = new System.Windows.Forms.Timer(); 
    } 

    private void InitializeTimer() 
    { 
     this.searchProgressTimer.Interval = 250; 
     this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick); 
    } 

    void searchProgressTimer_Tick(object sender, EventArgs e) 
    { 
     searchProgressBar.Increment(1); 
     if (searchProgressBar.Value == searchProgressBar.Maximum) 
      this.searchProgressTimer.Stop(); 
    } 

    private void SearchDatabase_Click(object sender, EventArgs e) 
    { 
     this.searchProgressTimer.Start(); 

     // Time-consuming operation 
     String filename = @"http://www.bankofengland.co.uk/publications/Documents/quarterlybulletin/qb0704.pdf"; 
     WebClient webClient = new WebClient(); 
     webClient.DownloadFileAsync(new Uri(filename), @"file.pdf"); 
     int test; 
     for (int i = 0; i < 100000; i++) 
      for (int j = 0; j < 100000; j++) 
       test = i + j; 


     this.searchProgressTimer.Stop(); 

    } 
} 

(該功能被命名爲一點點奇怪,因爲實際的耗時的操作是一個數據庫搜索,但該代碼,雖然正常工作,是非常漫長,並涉及)。

調試此代碼只是向我顯示SearchButton_Click事件處理程序正確觸發,但代碼從不跳轉到事件處理程序。有任何想法嗎?

+4

我看不到任何InitializeTimer()的調用 – 2012-07-13 18:41:32

+0

把斷點'searchProgressBar.Incriment(1)'。您可以通過單擊該行左側的邊距來完成此操作。一個紅點會出現讓你知道一個斷點在那裏。在調試器中運行該程序,查看斷點是否被命中。 – 2012-07-13 18:43:31

+0

http://stackoverflow.com/a/11033200/763026 – 2012-07-14 14:31:48

回答

2

所以1)我沒有看到InitializerTimer()的調用的任何地方。

和2)System.Windows.Forms.Timer在UI線程上產生它的tick事件..這是你耗時操作的同一個線程。您需要偶爾對消息泵進行控制,以便進行處理。

+0

這兩個都是問題所在。我更新了代碼以包含對「BackgroundWorker」及其功能的調用。我打算接受你的答案,但是我應該編輯我的問題並*添加*可以工作的代碼? – 2012-07-13 19:10:03

+0

在問題中添加工作代碼可以讓未來的搜索者更快地得到答案。你決定。 – 2012-07-13 20:56:31

3

你在這裏做的是有點混亂。假設你實際上正在初始化計時器 - 我認爲這是發生了什麼...

​​類完全運行在窗體的消息循環中,因此它不能在該函數在該線程上運行時觸發。因此,雖然你的計時器Start()Click()函數在與定時器相同的線程上運行,所以定時器在該函數返回之前不會觸發。但是,在該函數返回之前您再次返回定時器Stop()

也許你想看看Threading.Timer。雖然 - 理想上你正在做的「工作」 - 無論是數據庫操作還是隻是一個愚蠢的嵌套for循環 - 應該發生在不同的線程上,以便GUI的消息循環仍然可以處理。

如果你爲此產生了一個不同的線程,不要忘記在主UI線程上調用任何UI更改或對UI元素的更改!

1

調試這個代碼只是向我表明了SearchButton_Click事件處理火災正確,但代碼永遠不會跳轉到searchProgressTimer_Tick事件處理程序。

請嘗試移動IntializeTimer()程序到你的窗體的構造,因爲它看起來像你從來沒有佈線了定時器的Tick事件:

public Form1() 
{ 
    InitializeComponent(); 
    this.searchProgressTimer = new System.Windows.Forms.Timer(); 
    this.searchProgressTimer.Interval = 250; 
    this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick); 
} 
2

這是因爲你的圖形用戶界面更新是在同一個線程中發生數據庫操作。數據庫操作應在不同的線程中完成,並調用GUI線程通知更新。看看這個,因爲它解釋得很好。

http://www.dotnetperls.com/progressbar

+1

如果你在同一個線程中完成你的時間密集型工作,你的進度條永遠不會正常工作。後臺工作人員是爲了這樣的任務而製作的。 – 2012-07-13 18:49:50

相關問題