C# 以线程安全的方式创建新窗口
我使用信号器将消息向上推送到服务器,向下推送到特定的客户端 当我发送消息时,接收客户端从我的signalR服务器发送一个ReceiveMessage函数调用,该调用映射到我的应用程序中的静态类函数。然后,静态类尝试执行C# 以线程安全的方式创建新窗口,c#,wpf,signalr,C#,Wpf,Signalr,我使用信号器将消息向上推送到服务器,向下推送到特定的客户端 当我发送消息时,接收客户端从我的signalR服务器发送一个ReceiveMessage函数调用,该调用映射到我的应用程序中的静态类函数。然后,静态类尝试执行newchat()(我的消息窗口类)以在接收端打开消息窗口 这个抛出的调用线程必须是STA,因为许多UI组件都需要它。 我以前曾与代表一起处理过简单的表单元素(比如更改文本框),但我不知道如何在这种情况下应用它。当我读到Invoke时,它是在某种形式的表单对象上调用的,在我的情况下
newchat()
(我的消息窗口类)以在接收端打开消息窗口
这个抛出的调用线程必须是STA,因为许多UI组件都需要它。
我以前曾与代表一起处理过简单的表单元素(比如更改文本框),但我不知道如何在这种情况下应用它。当我读到Invoke
时,它是在某种形式的表单对象上调用的,在我的情况下它不存在吗
TLDR;如何从静态类函数调用创建和显示表单的新实例最简单的方法:使用在GUI线程上执行创建:
App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));
SynchronizationContext syncContext = SynchronizationContext.Current;
更难:创建一个新的STA线程,并在其上创建新窗口
后一个选项更难,因为您将有多个GUI线程,并且需要确保跟踪操作,以便在每种情况下使用正确的线程。除非您有特定的理由让多个GUI线程坚持使用easy选项。Easter:使用在GUI线程上执行创建:
App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));
SynchronizationContext syncContext = SynchronizationContext.Current;
更难:创建一个新的STA线程,并在其上创建新窗口
后一个选项更难,因为您将有多个GUI线程,并且需要确保跟踪操作,以便在每种情况下使用正确的线程。除非您有特定的理由让多个GUI线程坚持使用easy选项。使用当前GUI的线程调度程序。然后调用invoke。典型例子:
Application.Current.Dispatcher.Invoke(() => {
var win = new Window();
win.show();
});
使用当前GUI的线程调度程序。然后调用invoke。典型例子:
Application.Current.Dispatcher.Invoke(() => {
var win = new Window();
win.show();
});
您必须在UI线程中调用代码。为此,您需要对同步上下文的引用。 假设您从UI线程调用了以下代码:
App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));
SynchronizationContext syncContext = SynchronizationContext.Current;
在此,您可以参考上下文
然后在回调方法中(在后台线程(非UI)中接收到消息后),可以执行以下操作:
syncContext.Post((state) =>
{
Window w = new Window();
}, ...);
lambda表达式中的代码代表UI线程执行。
据我所知,在“Control.Invoke”和“Dispatcher.Invoked”两种方法中,这实际上都是在幕后发生的。您必须在UI线程中调用代码。为此,您需要对同步上下文的引用。 假设您从UI线程调用了以下代码:
App.MainWindow.Dispatcher.BeginInvoke((Action)(() => { new Chat(); }));
SynchronizationContext syncContext = SynchronizationContext.Current;
在此,您可以参考上下文
然后在回调方法中(在后台线程(非UI)中接收到消息后),可以执行以下操作:
syncContext.Post((state) =>
{
Window w = new Window();
}, ...);
lambda表达式中的代码代表UI线程执行。
据我所知,在“Control.Invoke”和“Dispatcher.Invoked”两种方法中,这实际上都是在幕后发生的。请注意,您应该注意BeginInvoke()和Invoke()方法之间的区别——前者将在另一个线程上异步执行操作,而后者则同步执行操作。调用调用,因为它们是同步的,在某些情况下可能会导致死锁,因此应仅在适当时使用。请参阅注意,您应该注意BeginInvoke()和Invoke()方法之间的区别——前者将在另一个线程上异步执行操作,而后者将同步执行操作。调用调用,因为它们是同步的,在某些情况下可能会导致死锁,因此应仅在适当时使用。看见