我遇到线程概念以及如何使用它们的问题。
我正在尝试编写一个相当基本的聊天程序(作为更大程序的一部分),它目前的工作原理如下:
'NetworkSession'类在循环中的单独线程上接收来自服务器的输入。如果它收到表明它应该打开一个新的聊天窗口的输入,它会构造一个新的WPF类(ChatWindow)并显示它。
最初我收到的错误是“调用线程必须是STA,因为许多UI组件都需要这个。”所以我将线程设置为STA,但现在当然WPF表单不可用,因为它在与阻塞循环相同的线程上运行。
所以我的问题是如何在另一个线程中创建一个WPF表单的新实例。
我已经看过很多关于此问题的讨论,但它倾向于处理从已经构建的表单中运行委托。
这是一些代码。
while (Connected) //this loop is running on its own thread
{
Resp = srReceiver.ReadLine();
if (Resp.StartsWith("PING")) SendToServer("PONG");
if (Resp.StartsWith("CHAT FROM"))
{
String[] split = Resp.Split(' ');
Console.WriteLine("Incoming Chat from {0}", split[2]);
bool found = false;
if (Chats.Count != 0)
{
foreach (ChatWindow cw in Chats)
{
if (cw.User == split[2])
{
found = true;
cw.AddLine(cw.User, split[3]); // a function that adds a line to the current chat
}
}
}
if (!found)
{
ChatWindow temp = new ChatWindow(split[2], split[3]);
Chats.Add(temp); //this is a collection with T = ChatWindow
temp.Show();
}
}
}
答案 0 :(得分:3)
如果您正在从UI线程构建NetworkSession,则可以获取对稍后可以操作UI的当前Dispatcher
的引用。
<强> NetworkSession.cs 强>
private Dispatcher _dispatcher;
public NetworkSession()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
//any thread can call this method
public void DoStuff()
{
Action action = () =>
{
ChatWindow temp = new ChatWindow(split[2], split[3]);
Chats.Add(temp);
temp.Show();
};
_dispatcher.BeginInvoke(action);
}
答案 1 :(得分:1)
我从here获取的以下代码为我工作:
public static void StartChatWindow()
{
Thread thread = new Thread(() =>
{
ChatWindow chatWindow = new ChatWindow();
chatWindow.Chat(); // Do your stuff here, may pass some parameters
chatWindow.Closed += (sender2, e2) =>
// Close the message pump when the window closed
chatWindow.Dispatcher.InvokeShutdown();
// Run the message pump
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
答案 2 :(得分:0)
您真正需要做的是在主UI线程上构建窗口/表单。您可能需要定义一个可以从网络线程调用的委托,并且该委托应该附加一个将调用this.Dispatcher.BeginInvoke() - &gt;的方法。在其中构建窗口。
执行UI线程上的代码需要this.Dispatcher.BeginInvoke()调用,否则即使使用委托,代码也会在网络线程上执行。
委托和创建新聊天窗口的方法都应该附加到MainWindow ...