【问题标题】:How to construct a new WPF form from a different thread in c#如何从 C# 中的不同线程构造新的 WPF 表单
【发布时间】:2010-10-17 16:13:43
【问题描述】:

我对线程的概念以及如何使用它们感到困惑。

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

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

                }

            }

        }

【问题讨论】:

    标签: c# wpf multithreading


    【解决方案1】:

    如果您从 UI 线程构建 NetworkSession,则可以获取对当前 Dispatcher 的引用,以便稍后操作 UI。

    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);
    }
    

    【讨论】:

      【解决方案2】:

      我从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();
          }
      

      【讨论】:

        【解决方案3】:

        您真正需要做的是在您的主 UI 线程上构建窗口/表单。您可能需要定义一个可以从网络线程调用的委托,并且该委托应该附加一个方法,该方法将调用 this.Dispatcher.BeginInvoke() -> 您将在其中构建您的窗口。

        this.Dispatcher.BeginInvoke() 调用是在 UI 线程上执行代码所必需的,否则即使使用委托,代码也会在网络线程上执行。

        委托和创建新聊天窗口的方法可能都应该附加到 MainWindow...

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多