2012-07-30 90 views
1

我正在使用signalR將消息推送到服務器並向下推送到特定客戶端。以線程安全的方式創建新窗口

當我發送一條消息時,接收客戶端發送一個來自我的signalR服務器的ReceiveMessage函數調用,該服務器映射到我的應用中的靜態類函數。靜態類然後試圖做new Chat()(我的消息傳遞窗口類)在接收端打開消息窗口。

這將引發calling thread must be STA, because many UI components require this.

我以前與代表工作簡單表單元素(如改變文本框),但我不明白如何應用,在這種情況下。當我讀到Invoke時,它被稱爲某種形式的對象,這在我的情況中不存在?

TLDR;我如何創建和靜態類函數調用

回答

5

使用當前的GUI線程調度程序。然後調用invoke。例如:

Application.Current.Dispatcher.Invoke(() => { 
     var win = new Window(); 
     win.show(); 
}); 
+1

請注意,您應該瞭解BeginInvoke()與Invoke()方法之間的區別 - 前者將在另一個線程上異步執行操作,而後者將同步執行操作。調用調用是因爲它們是同步的,在某些情況下可能會導致死鎖,所以只能在適當的時候使用。請參閱http://stackoverflow.com/questions/229554/whats-the-difference-between-invoke-and-begininvoke – CrimsonX 2012-07-30 18:01:02

+0

+1注意事項,要點。 – SynerCoder 2012-07-30 19:01:30

2

最簡單的表現形式的新實例:利用App.MainWindow.Dispatcher執行GUI線程的創建:

App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); })); 

哈爾德:創建一個新的STA線程,並在其上創建新的窗口。

後一個選項比較困難,因爲您將擁有多個GUI線程,並且需要確保您跟蹤操作,以便在每種情況下使用正確的線程。除非你有一個特別的理由讓多個GUI線程使用easy選項。

0

您必須在UI線程中調用您的代碼。要做到這一點,你需要引用同步上下文。 假設你從UI線程調用下面的代碼:

SynchronizationContext syncContext = SynchronizationContext.Current; 

特此你有上下文的參考。

然後在回調方法(在後臺線程接收消息(未UI)之後),可以執行以下操作:

syncContext.Post((state) => 
       { 
        Window w = new Window(); 

       }, ...); 

在λ表達式的代碼代表UI線程的執行。 據我所知這是在「Control.Invoke」和「Dispatcher.Invoked」方法中幕後實際發生的事情。