2011-02-08 84 views
2

下面的代碼是我的問題的簡化版本:多線程應用程序上的數據綁定?

public partial class Form1 : Form 
{ 
    BackgroundWorker bw; 
    Class myClass = new Class(); 

    public Form1() 
    { 
     InitializeComponent(); 

     bw = new BackgroundWorker(); 
     bw.DoWork += new DoWorkEventHandler(bw_DoWork); 
     label1.DataBindings.Add("Text", myClass, "Text", true, DataSourceUpdateMode.Never); 
    } 

    void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     myClass.Text = "Hi"; 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     bw.RunWorkerAsync(); 
    } 
} 

public class Class : INotifyPropertyChanged 
{ 
    private string _Text; 

    private void SetText(string value) 
    { 
     if (_Text != value) 
     { 
      _Text = value; 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public string Text 
    { 
     get { return _Text; } 
     set { SetText(value); OnPropertyChanged(new PropertyChangedEventArgs("Text")); } 
    } 

    protected void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     if (PropertyChanged != null) PropertyChanged(this, e); 
    } 
} 

什麼情況是,當我點擊Button1的(它調用button1_Click)在label1文本不更新。這是因爲label1.Text屬性在內部試圖從我的BackgroundWorker的線程中更改,該線程會在內部導致異常。一般來說,解決這類問題最好的辦法是什麼?如果您必須從不同的線程更新Class.Text屬性,但還必須具有綁定的控件,那麼將更改此代碼的哪一部分?

+0

只有在* BGW完成後綁定*。使用RunWorkerCompleted事件。 – 2011-02-08 20:06:22

回答

1

試試這個:

//This is the handler to execute the thread. 
void DoWork(object sender, EventArgs a) { 

Action updateControl =()=>myClass.Text = "Blah"; 

if(myForm.InvokeRequired) { 

    myForm.Invoke(updateControl); 

} 
else {updateControl();} 

}

背景工作者線程在這個例程執行。

1

基本上,您必須使用工作線程中的InvokeBeginInvoke來執行實際更新。從主UI線程以外的線程直接與控件進行交互是非法的(除非它已經被寫入)。使用lambda語法,使用InvokeBeginInvoke有點比以前更清潔。例如:

void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Invoke(new Action(() => myClass.Text = "Hi")); 
} 

這將執行UI線程上的代碼。然而,BackgroundWorker類(我假設你正在使用,基於這裏的名字)有一個ReportProgress函數,這引發了UI線程上的ProgressChanged事件。它使用了我上面描述的相同機制,但它可能會更清晰一些。選擇是你的。

0

只允許UI線程更改UI控件的屬性。你的BackgroundWorker不應該這樣做。

幸運的是BackgroundWorker支持ProgressChanged事件。您的DoWork應該提出這個問題,並且可以更新UI,因爲後臺工作人員會將其封送回UI線程。