为什么我的线程在显示Windows窗体后立即终止?

我有一个Windows窗体应用程序(Form1),允许用户打开另一个窗体(FormGraph)。 为了打开FormGraph应用程序,我使用一个打开它的线程。
这是线程正在运行的代码:

private void ThreadCreateCurvedGraph() { FormGraph myGraph = new FormGraph(); myGraph.CreateCurvedGraph(...); myGraph.Show(); } 

我的问题是myGraph在打开后myGraph关闭。
1)有谁知道为什么会这样,以及如何让myGraph保持开放状态?
2)用户关闭myGraph ,如何终止线程?
非常感谢!

问题不在发布的代码段中。 您需要使用Application.Run()或Form.ShowDialog()启动新的消息循环。 您还需要处理线程属性,因此适合充当UI线程。 例如:

  Thread t = new Thread(() => { Application.Run(new Form2()); // OR: //new Form2().ShowDialog(); }); t.SetApartmentState(ApartmentState.STA); t.IsBackground = true; t.Start(); 

这里有一些尴尬的选择。 表单不能由主线程上的任何表单拥有,这通常会导致Z顺序问题。 当UI线程的主窗体关闭时,您还需要做一些有意义的事情。 通过使用IsBackground在这里解决了问题。

Windows旨在支持在一个线程上运行的多个窗口。 如果你真的需要,只使用这样的代码。 你永远不应该……

您的主要问题是您没有在新线程中建立消息泵。

校验

运行多个UI线程

有关如何使用多个线程(每个表单/表单组一个)运行高性能用户界面的详细概述。

你基本上错过的是调用Application.Run来在单独的UI线程上设置消息泵。

我认为一旦消息泵的最后一种forms关闭 – 它将自行处理并结束。

请注意,所有这些假设你想在一个单独的UI线程中打开窗口…否则你需要调用回主UI线程来创建窗口的所有操作,因此它会附加到现有的消息泵。 两者都有好的情况 – 一个保持简单,另一个允许更多的性能,因为每个窗口都有一个单独的消息泵,因此可以单独行动 – 这例如在交易应用程序中使用很多,可能需要更新图表如果在UI中运行单线程,则有许多屏幕并且有瓶颈。

根据经验,您应该避免从线程操纵UI(创建表单是对UI的一种操作)。 您应该始终从主线程操纵UI。

表单正在关闭,因为该线程已完成,因此随其资源(表单)一起被释放。 要使线程保持运行,您需要一个循环

例如

 private void ThreadCreateCurvedGraph() { FormGraph myGraph = new FormGraph(); myGraph.CreateCurvedGraph(...); myGraph.Show(); while (myGraph.IsOpen) { //process incoming messages <- this could be fun on a thread.... } } 

您需要一种设置IsOpen的方法(如超时或按钮),显然您需要实际创建IsOpen作为表单的属性,并在创建表单时将其设置为true。

我将在这里添加与其他用户相同的...你应该有充分的理由不使用主线程。

如果为表单准备数据需要一段时间,则可以在单独的线程中执行此操作以使应用程序保持响应。 数据准备好后,您可以将对象返回到主线程,让它显示它。

您应该为表单中的对象声明一个变量而不是方法中的本地变量,以便在退出线程时它仍然存在。

当您准备好显示表单时,可以使用Invoke方法进行将在主线程中执行的方法调用。

不要在非主线程中创建和显示表单。 在主表单线程中执行。

或者这样做:

 private void ThreadCreateCurvedGraph() { FormGraph myGraph = new FormGraph(); myGraph.CreateCurvedGraph(...); Application.Run(myGraph); } 

但第一版更好

为什么要在新线程上创建表单? 有时您需要使用新线程,但有时您可以在主线程上使用form.ShowDialog()。

如果您将表单显示为对话框怎么样? 您可以使用

 private void ThreadCreateCurvedGraph() { FormGraph myGraph = new FormGraph(); myGraph.CreateCurvedGraph(...); myGraph.ShowDialog(); } 

这样调用将阻塞,直到myGraph表单关闭。 正如你在一个独立的线程上创建myGraph一样,调用阻塞的ShowDialog应该只阻止该线程。

也许这是垃圾收集:

ThreadCreateCurvedGraph()退出后, myGraph超出范围并关闭。

您需要组织线程的方式来保持实例并等待(使用阻塞等待)它关闭。

编辑:例如添加:

 Application.Run(myGraph) 

到方法的最后。
(见TomTom的评论)