C# 多UI线程-Winforms

C# 多UI线程-Winforms,c#,winforms,multithreading,user-interface,C#,Winforms,Multithreading,User Interface,我想在我的应用程序中创建多个UI线程。我已经模拟了如下场景。我在后台线程中单击按钮创建一个新窗口/窗体 请注意,-I正在执行IsBackground=true,因为当用户关闭主窗体时,子窗体/窗口也应该关闭有没有更干净/优雅的方法来达到同样的效果? 编辑-我想为每个窗口创建专用的UI线程。我会的 有10个这样的窗口并行显示实时数据 解决方案-这样可以吗?(根据下文和Hans的评论) 已设置公寓状态(请参见上面的代码) 弄乱线只会迟早咬到你 从MSDN: Windows窗体中的控件绑定到特定线程,

我想在我的应用程序中创建多个UI线程。我已经模拟了如下场景。我在后台线程中单击按钮创建一个新窗口/窗体

请注意,-I正在执行IsBackground=true,因为当用户关闭主窗体时,子窗体/窗口也应该关闭有没有更干净/优雅的方法来达到同样的效果?


编辑-我想为每个窗口创建专用的UI线程。我会的 有10个这样的窗口并行显示实时数据

解决方案-这样可以吗?(根据下文和Hans的评论) 已设置公寓状态(请参见上面的代码)


弄乱线只会迟早咬到你

从MSDN:

Windows窗体中的控件绑定到特定线程,并且不是线程安全的。因此,如果从不同的线程调用控件的方法,则必须使用控件的某个调用方法将调用封送到适当的线程

当然,您可以使用任意多的线程,但不要试图创建一个变通方法,以便能够使用不同的线程来更新UI。改为使用工作线程/后台线程中的
Invoke
/
invokererequired


使用扩展方法使它更简洁:

我认为您需要将线程的单元状态设置为单线程,如这里和这里所示:
t.SetApartmentState(ApartmentState.STA)
。不过,我不知道在后台线程上是否可以这样做


另一件我希望您注意的事情是MDI(例如,多文档接口)。您真的需要将不同的表单显示为自己的窗口,还是将它们作为文档显示在一个公共表单中?当然,您可能有理由创建多个UI线程。

您可以为每个子窗体处理MainForm.Closing事件并调用subForm.Close(封送到右线程)


不过,我不知道为什么要将表单放在单独的线程上。你不能在主线程上以非模态方式显示子窗体吗?

为什么不简单地使用后台工作程序?你不应该在主应用程序关闭后继续显示表单,这太混乱了。你为什么还需要另一个线程呢?只需在主线程上创建表单,然后调用
f.Show()
。这有多种方法。然而,正如@Ramhound已经提到的,您可能想看看
BackgroundWorker
,因为它有一些不错的事件另一种选择是
Task
.svick-我想为每个窗口创建专用的UI线程。我将有10个这样的窗口并行显示实时数据。拥有10个cpu核的机器是非常不寻常的。调用Thread.SetApartmentState()是必需的。如果您想要干净地关闭,那么您必须将表单存储在一个列表中,这样您就可以f.Invoke()调用Application.Exit()。在多个线程上显示窗口几乎从来都不是一个错误。这些窗口没有Z顺序关系,任意消失在另一个应用程序的窗口后面。我想为每个窗口创建专用的UI线程。我将有10个这样的窗口并行显示实时数据-对MTA/STAMy问题给出了一个很好的总结,即在主窗体关闭时关闭单个窗口。那么,当主窗体关闭时,我应该从工作线程调用什么(上面的代码是w.r.t)?抱歉,我有点困惑。如果你开始以正确的方式(而不是你问题中的解决方案)处理线程,这些表单将关闭尼克-生成和布局视觉元素的成本可能会变得太高,以至于单个线程无法跟上UI密集型应用程序的步伐。
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var thread = new Thread(() =>
            {
                Form f = new Form();
                Application.Run(f);
            });

            // thread.IsBackground = true; -- Not required. See Solution below
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }
    }  
}
protected override void OnClosed(EventArgs e)
{
    Application.Exit();
}