以线程安全的方式创建新窗口

时间:2012-07-30 14:36:35

标签: c# wpf signalr

我正在使用signalR将消息推送到服务器并向下推送到特定客户端。

当我发送消息时,接收客户端从我的signalR服务器发送一个ReceiveMessage函数调用,该函数映射到我的应用程序中的静态类函数。然后,静态类尝试执行new Chat()(我的消息传递窗口类)以在接收端打开消息窗口。

这会抛出calling thread must be STA, because many UI components require this.

之前我曾与代表合作过简单的表单元素(比如更改文本框),但我不明白如何在这种情况下应用它。当我读到Invoke时,会在某种形式对象上调用它,这在我的情况下是不存在的?

TLDR;如何从静态类函数调用

创建和显示表单的新实例

3 个答案:

答案 0 :(得分:5)

使用当前GUI的线程调度程序。然后调用invoke。例如:

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

答案 1 :(得分:2)

最简单:使用App.MainWindow.Dispatcher在GUI线程上执行创建:

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

更难:创建一个新的STA线程,并在其上创建新窗口。

后一个选项更难,因为您将拥有多个GUI线程,并且需要确保跟踪操作,以便在每种情况下使用正确的线程。除非您有特定的理由让多个GUI线程坚持使用easy选项。

答案 2 :(得分:0)

您必须在UI线程中调用您的代码。为此,您需要引用同步上下文。 假设您从UI线程调用以下代码:

SynchronizationContext syncContext = SynchronizationContext.Current;

因此你得到了对上下文的引用。

然后在回调方法中(在后台线程(而不是UI)中接收到消息后),您可以执行以下操作:

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

                }, ...);

lambda表达式中的代码代表UI线程执行。 据我所知,这是“Control.Invoke”和“Dispatcher.Invoked”方法中幕后实际发生的事情。