2012-01-17 34 views
2

我有兩個關於使用BackgroundWorker的問題:在C#中使用BackgroundWorker?

1)假設你有函數A和函數B.函數A創建一個運行函數B的BackgroundWorker。所以BackgroundWorker現在在一個單獨的線程上運行函數B.函數B是一個無限的while循環,我打算長時間運行。函數A使用BackgroundWorker後,它會返回。因此,現在已經返回了啓動BackgroundWorker(函數A)的函數,BackgroundWorker線程是否繼續在後臺運行?或者它是否停止運行函數B,因爲實例化它的函數已經返回?如果它停止,我將如何使它功能B繼續運行,即使功能A已返回?

2)我需要從BackgroundWorker創建的單獨線程訪問窗體窗體項目(即文本框)。但是,如果我嘗試從非主線程的線程訪問窗體窗體項目,則會出現交叉線程錯誤。我怎麼能從一個單獨的線程安全地訪問窗體窗體項目?我基本上需要不斷從一個單獨的線程更新文本框。我知道一個BackgroundWorker有一個名爲「RunWorkerCompleted」的成員,並在BackgroundWorker完成其工作後運行。它允許我從中訪問Window窗體項目。但是,我需要在線程期間訪問窗體表單項,而不是在完成之後。我怎麼能通過一個線程安全地訪問它們?如果這不可行,那麼對於這個問題還有其他可能的解決方案嗎?

回答

4

1)函數A返回後,BackgroundWorker將繼續運行。

2)創建一個ProgressChanged事件處理函數,用於更新文本框,並在需要更改文本時使BackgroundWorker調用ReportProgress。當然,您必須將BackgroundWorker設置爲ProgressChanged事件可以讀取的屬性。這是有效的,因爲在UI線程上調用了ProgressChanged事件處理程序。

+0

謝謝。我使用ProgressChanged,但它仍然給我一個交叉線程錯誤。任何想法爲什麼? – fdh 2012-01-17 04:57:40

+0

你(@Farhad)嘗試了我給出的代碼片段嗎? – 2012-01-17 04:59:16

+0

@Amir Palsapure感謝您的幫助。你的回答對我來說有點複雜(沒有你的錯),這個看起來更容易一點,所以我決定嘗試一下。我剛剛開始C#,所以這個答案似乎更容易理解。再次感謝你的幫助。 – fdh 2012-01-17 05:02:37

1

吉姆的回答是正確的。

在第二部分,你說

我需要從一個BackgroundWorker創建一個單獨的線程訪問Window窗體項目(即文本框)。

所以,如果你想要做這樣,只有那麼你將需要現在要做的是創建一個像下面

public static class ControlExtensions 
{ 
    public static void Invoke(this Control control, Action action) 
    { 
     if (control.InvokeRequired) control.Invoke(new MethodInvoker(action), null); 
     else action.Invoke(); 
    } 
} 

現在,當您訪問從非UI線程文本框的擴展方法,你需要這樣做

txtBox.Invoke(() => { txtBox.Text = "Text Changed from Non-UI thread"; }); 

希望這可以幫助你。

1

對於第二個問題:

即使我面臨同樣的問題一次。所以使用了_DoWork方法。
這是如何工作對我來說

private void bgwLongTask_DoWork(object sender, DoWorkEventArgs e) 
{ 

    my long task 
    { 
     //in between the long task, i want to udpate the datagrid view dataGridView1 

     if (dataGridView1.InvokeRequired) 
     dataGridView1.Invoke(myGridBindDelegate); 
     else 
     BindDataToGrid(); 
    } 
} 

這裏myGridBindDelegate是調用數據網格視圖結合方法的委託。

delegate void GridBindDelegate(); 
    GridBindDelegate myGridBindDelegate; 
    myGridBindDelegate = BindDataToGrid; 

    private void BindDataToGrid() 
    { 
     dataGridView1.DataSource = dt; //dt is a datatable which is public 
     dataGridView1.Refresh(); 
    } 

爲我工作。