2010-08-11 86 views
2

我的問題是這樣的:訪問Windows從BackgroundWorker的DoWork的控制

我有我已經放在一個LayoutPanel Windows窗體,當形式加載,多個控件,如:文本框和標籤被添加到LayoutPanel。

然後在點擊一個按鈕,我需要處理用戶對這些動態創建的控件輸入的數據。對於該purpouse,我使用Backgroundworker,它應該採用這些控件並讀取它們的數據。

我的問題是Backgroundworker不允許我從DoWork方法訪問控件,但我需要這樣做,因爲我將報告操作的進度。

這裏是我的代碼部分,以澄清這一概念:

private void frmMyForm_Load(object sender, EventArgs e) 
    { 
     //I add multiple controls, this one is just for example 
     LayoutPanel1.add(TextBox1); 

     .... 
    } 

private void bgwBackground_DoWork(object sender, DoWorkEventArgs e) 
    { 

     foreach (Control controlOut in LayoutPanel1.Controls) 
     { 
      //do some stuff, this one is just for example 
      string myString = controlOut.Name; //-> Here is the error, cant access controls from different Thread. 
     } 
    } 

設置文本簡單的只是使用委託,但如何讓整個父控制操縱子控件(只是爲了獲取信息,我不想設置任何數據,只需要獲取名稱,文本,類似的東西)。

希望我自己清楚,謝謝大家。

回答

10

您只能從GUI線程訪問Windows窗體控件。如果你想從另一個線程操縱它們,你將需要使用Control.Invoke方法來傳入一個委託來在GUI線程上執行。在你的情況,你應該能夠做到這一點:

private void bgwBackground_DoWork(object sender, DoWorkEventArgs e) 
{ 
    foreach (Control controlOut in LayoutPanel1.Controls) 
    { 
     this.Invoke(new MethodInvoker(delegate { 
      // Execute the following code on the GUI thread. 
      string myString = controlOut.Name; 
     })); 
    } 
} 

我喜歡定義一個擴展方法,它允許我使用清潔lambda語法:

// Extension method. 
internal static void Invoke(this Control control, Action action) { 
    control.Invoke(action); 
} 

// Code elsewhere. 
this.Invoke(() => { 
    string myString = controlOut.Name; 
}); 
+0

它的工作非常適合我,謝謝許多。 – lidermin 2010-08-12 16:50:15

1

正如你已經知道,從非UI線程以外的任何線程訪問控制值是一大禁忌。我想說一個合理的實現是使用.NET同步機制(如WaitHandle)在UI線程更新您選擇的線程安全數據結構時掛起後臺線程。

這個想法是,你的後臺線程通知UI線程(通過你已經熟悉的委託機制)它需要信息,然後等待。當UI完成將信息填充到共享變量時,它將重置WaitHandle,並且後臺工作人員恢復。

沒有寫出並測試所有的代碼,讓我給你幾個資源: