2009-07-01 242 views
8

我正在寫一個小聊天應用,和我有這樣的事件處理程序:C#,事件處理程序和線程

void o_Typing(object sender, EventArgs e) 
{ 
    MessageBox.Show("Fired!"); 
    this.Text = "Fired!"; 
} 

o_Typing是從TabPage派生的類的方法。基本上,我希望每個對話都有自己的選項卡。

事件處理程序由我的Chat對象觸發,該對象在另一個線程中運行。我有1個用戶界面線程,另一個線程用於每個聊天對話(以保持輪詢服務器的新數據)

當事件被觸發時,彈出MessageBox,但Tab標題不會改變。事件觸發一次後,它再也不會觸發,這讓我相信這個事件在工作線程中被調用,儘管它在UI線程中定義。

如何讓我的事件從工作線程調用,並使用Invoke()讓它們在UI線程上執行?

回答

11

有兩種選擇:

1)使事件處理線程安全的:在需要交談的UI線程的任何事件處理程序使用Control.Invoke/BeginInvoke

2)在引發事件之前,使工作線程編組回到UI線程 - 換句話說,使用Control.Invoke作爲引發事件過程的一部分,這樣事件處理程序將全部在UI線程中調用。根據您的應用程序的結構,您可能不希望事件提升組件明確瞭解UI,但在構建時,您可以傳入一個ISynchronizeInvoke(其中Control實現)和您的組件可以使用它來提高其事件在正確的線程上。當然,如果每個事件處理程序都很樂意在同一個線程上運行,那麼它就可以工作(無論如何) - 但通常情況就是這樣。你會寫這樣的:

protected void OnFoo(EventArgs args) 
{ 
    if (sync != null && sync.InvokeRequired) 
    { 
     sync.Invoke((Action) delegate { OnFoo(args) }, null); 
     return; 
    } 
    EventHandler handler = Foo; // Where Foo is the event name 
    if (handler != null) 
    { 
     handler (this, args); 
    } 
} 
6

如果您在工作線程執行的代碼中激發事件,則訂閱該事件的所有方法都將在該工作線程下執行。

對於GUI元素,您需要查看Invoke方法。

問候

+0

感謝您的答案,請參閱我的編輯。 – 2009-07-01 06:22:34

+0

你不知道。您可以在工作線程上調用該事件,並且每個訂閱服務器應檢查它是否在正確的線程上,並在需要時調用本身。 – 2009-07-01 06:24:14