2012-02-29 39 views
3

我正在編寫一個應用程序,通過GPIB命令與多個設備進行通信,並在某些設備上運行測試。我建立了一個類TestProcedure,它將啓動一個新線程並運行測試。在整個測試過程中,我已經設置了幾個自定義事件來將信息發送回GUI。下面是一個簡單事件的例子:C#:事件和線程安全GUI更新

public event InformationEventHandler<string> TestInfoEvent; 
    /// <summary> 
    /// Event raised when information should be passed back to the main testing form. 
    /// </summary> 
    /// <param name="s">Information to send back to form.</param> 
    private void OnInfo(string s) 
    { 
     if (TestInfoEvent != null) 
      TestInfoEvent(this, s); 
    } 

這將通過GUI進行處理,更新一個文本框是這樣的:

TheTestProcedure.TestInfoEvent += new TestProcedure.InformationEventHandler<string> 
           (InfoOccurred); 
.... 
private void InfoOccurred(Object sender, string s) 
{ 
    this.textBox1.Text = s + Environment.NewLine + this.textBox1.Text; 
    if (this.textBox1.Text.Length > 10000) 
     this.textBox1.Text = this.textBox1.Text.Remove(1000); 
} 

此事件處理似乎是工作的罰款。我還沒有收到任何跨線程問題,總體而言,它一直在按預期工作。然而,在另一種形式中,我只是添加了一個類似的事件處理程序,它引發了一個跨線程異常。事件觸發,發送一個帶有一些信息的簡單類,這些信息顯示在InputTextBox(一個自定義的ComponentOne控件)中。特定的控件沒有.Invoke方法,所以我正在尋找替代解決方案來異步訪問它。

所以我的問題是,事件處理程序安全地訪問窗體上的控件?如果不是,事件處理程序如何觸發,並且有人可以幫助我教育我,或提供一些鏈接信息,以瞭解事件處理程序如何與窗體控件進行通信?我需要鎖定事件嗎?

回答

3

UI線程上的控件只能從UI線程訪問 - 任何來自其他線程的訪問都必然會引發問題。如果事件不在那裏,則需要使用InvokeRequiredBeginInvoke()將事件整理到正確的線程。

Example

+0

我應該添加一個調用到事件本身?這個工作是否與說文字框一樣? 編輯:對不起,剛纔看到你的例子我會看看 – Corey 2012-02-29 18:05:52

+0

你會首先在你的事件處理函數中檢查「InvokeRequired」,如果它返回「true」,你需要使用'的BeginInvoke()'。如果返回值爲'false',那麼您已經在UI線程中,因此您可以直接安全地訪問控件(例如,'txtName.Text = ...;'是有效的,如果您在錯誤的線程中,可能會失敗。) – xxbbcc 2012-02-29 18:07:53

+1

我修正了引用'BeginInvoke()'的答案,因爲你可能需要這個,而不是'Control.Invoke()'。 – xxbbcc 2012-02-29 18:11:38

1

你要創建一個委託回調Invoke()執行該測試InvokeRequired財產之後。以下代碼將以線程安全的方式處理添加。

TheTestProcedure.TestInfoEvent += new TestProcedure.InformationEventHandler<string> 
          (InfoOccurred); 

private void InfoOccurred(Object sender, string s) 
{ 
    LogMessage(s); 
} 

delegate void LogMessageCallback(string text); 

void LogMessage(String message) 
{ 
    if (this.textBox1.InvokeRequired) 
     this.Invoke(new LogMessageCallback(LogMessage), message); 
    else 
    { 
     this.textBox1.Text = s + Environment.NewLine + this.textBox1.Text; 
     if (this.textBox1.Text.Length > 10000) 
      this.textBox1.Text = this.textBox1.Text.Remove(1000); 
    } 
} 
+0

什麼是「日誌」?它應該是'this.InvokeRequired'。 – 2012-02-29 18:14:39

+0

對不起,修正了片段。 – Walk 2012-02-29 18:16:55