2012-07-30 58 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”方法中幕后实际发生的事情。