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

时间:2010-03-18 12:02:53

标签: c# winforms multithreading

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

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

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

9 个答案:

答案 0 :(得分:5)

问题不在发布的代码段中。您需要使用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旨在支持在一个线程上运行的多个窗口。如果确实必须使用,请仅使用此类代码。你永远不应该......

答案 1 :(得分:1)

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

检查

Run multiple UI Threads

详细了解如何使用多个线程(每个表单/表单组一个)运行高性能用户界面。

你基本上错过了对Application.Run的调用,以便在单独的UI线程上设置消息泵。

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

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

答案 2 :(得分:0)

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

或者这样做:

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

但第一版更好

答案 3 :(得分:0)

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

答案 4 :(得分:0)

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

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

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

答案 5 :(得分:0)

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

e.g。

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。

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

答案 6 :(得分:0)

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

答案 7 :(得分:-1)

也许这就是垃圾收集:

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

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

编辑例如添加:

Application.Run(myGraph)

到方法结束。
(见TomTom的评论)

答案 8 :(得分:-1)

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

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

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

相关问题