利用BackgroundWorker 組件進行異步作業

    學習Thread的時候,發現了一個問題:如下代碼,意在實現填充listbox的動作在新建的thread中工作,這樣不至於出現UI“假死”現象。
看代碼:

None.gifpublic void foo()
ExpandedBlockStart.gif        
{
InBlock.gif                listBox1.Items.Clear();
InBlock.gif
InBlock.gif                
for (int i = 0; i < 10000; i++)
ExpandedSubBlockStart.gif                
{
InBlock.gif                    listBox1.Items.Add(i.ToString());
ExpandedSubBlockEnd.gif                }

InBlock.gif           
ExpandedBlockEnd.gif        }

None.gif
None.gif        
private void button2_Click(object sender, EventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif            Thread thread 
= new Thread(new ThreadStart(foo));
InBlock.gif          
InBlock.gif            thread.Start();
ExpandedBlockEnd.gif        }


     執行出現錯誤:正在訪問的Control listbox1的線程並不是創建它的線程,也就是不一致(好像是這個意思),一查Msdn,才發現這樣的作業方式是Unsafe的,原因說了一大堆。推薦的方式是首先判斷兩個ThreadID是否一致,如果不一致,採用委託的方式進行safe的編程。

None.gif public delegate void Mydel();
None.gif
None.gif 
public void foo()
ExpandedBlockStart.gif        
{
InBlock.gif            
if (listBox1.InvokeRequired)
ExpandedSubBlockStart.gif            
{
InBlock.gif                Mydel del 
= new Mydel(foo);
InBlock.gif                
this.Invoke(del);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
else
ExpandedSubBlockStart.gif            
{
InBlock.gif                listBox1.Items.Clear();
InBlock.gif
InBlock.gif                
for (int i = 0; i < 10000; i++)
ExpandedSubBlockStart.gif                
{
InBlock.gif                    listBox1.Items.Add(i.ToString());
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif           
ExpandedBlockEnd.gif        }

None.gif
None.gif        
private void button2_Click(object sender, EventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif            Thread thread 
= new Thread(new ThreadStart(foo));
InBlock.gif          
InBlock.gif            thread.Start();
ExpandedBlockEnd.gif        }

          

     不知道是我寫的有問題,還是其他什麼原因,總之這樣是可以運行,但是好像不能達到我的目的。
     於是就看到了BackgroundWorker 組件:(msdn定義)BackgroundWorker 類別可以讓您在個別的專用執行緒上執行作業。執行耗費時間的作業 (例如下載和資料庫異動) 時,可能會讓使用者介面 (UI) 看起來像是已經停止反應。當您想要讓 UI 有所反應,但卻又必須面臨與這類作業相關的長時間延遲現象時,BackgroundWorker 類別可以提供便利的方案。

     

     若要設定背景作業,請加入 DoWork 事件的事件處理常式。在這個事件處理常式中呼叫耗時作業。若要啟動作業,請呼叫 RunWorkerAsync。若要接收進度更新的告知,請處理 ProgressChanged 事件。若要在作業完成時接收告知,請處理 RunWorkerCompleted 事件。

     您必須小心,不要在 DoWork 事件處理常式中操作任何使用者介面物件。相反地,請透過 ProgressChangedRunWorkerCompleted 事件,與使用者介面通訊。

     
     看例子:
     

None.gif public double foo2()  // 3.背景實際運算
ExpandedBlockStart.gif
        {
InBlock.gif
InBlock.gif            
double result=0;
InBlock.gif
InBlock.gif            Thread.Sleep(
5000);
InBlock.gif
InBlock.gif            
for (int i = 0; i < 100000; i++)
ExpandedSubBlockStart.gif            
{
InBlock.gif                result 
+= i;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return result;
ExpandedBlockEnd.gif        }

None.gif
None.gif        
private void button3_Click(object sender, EventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif            backgroundWorker1.RunWorkerAsync();  
//1.開始異步作業,跳轉DoWork事件
ExpandedBlockEnd.gif
        }

None.gif
None.gif        
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif            
this.progressBar1.Value = e.ProgressPercentage;  //結合ProgressBar顯示執行進度
ExpandedBlockEnd.gif
        }

None.gif
None.gif        
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif            textBox1.Text 
= e.Result.ToString(); //4.將作業結果返回UI
ExpandedBlockEnd.gif
        }

None.gif
None.gif        
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
ExpandedBlockStart.gif        
{
InBlock.gif           e.Result
= foo2();  //2.執行背景運算作業,並存儲結果(注意,不能在這裏與UI進行交互)
ExpandedBlockEnd.gif
        }

      運行後,可以看到,執行期間,並不影響你在UI做其他的動作,真正實現了異步作業。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章