如何从c#中的不同线程构造新的WPF表单

时间:2010-10-16 14:13:49

标签: c# wpf multithreading

我遇到线程概念以及如何使用它们的问题。

我正在尝试编写一个相当基本的聊天程序(作为更大程序的一部分),它目前的工作原理如下:

'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();

                }

            }

        }

3 个答案:

答案 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 ...