开发者

Why Does my Thread Terminate Immediately After Showing a Windows Form?

I have a Windows Form Application (Form1) that allow the user to open another Forms (FormGraph). In order to open the FormGraph App I use a thread that open it.

Here is the code that the thread is running:

开发者_高级运维private void ThreadCreateCurvedGraph()
{
    FormGraph myGraph = new FormGraph();
    myGraph.CreateCurvedGraph(...);
    myGraph.Show();
}

My problem is that myGraph closed right after it's open.

1) Does anyone know why this is happening and how to make myGraph stay open?

2) After the user closed myGraph, How do I terminate the thread?

Many thanks!


The problem is not in the posted snippet. You'll need to start a new message loop with Application.Run() or Form.ShowDialog(). You'll also need to take care of thread properties so it is suitable to act as a UI thread. For example:

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

There are some awkward choices here. The form cannot be owned by any form on your main thread, that usually causes Z-order problems. You'll also need to do something meaningful when the UI thread's main form is closed. Sloppily solved here by using IsBackground.

Windows was designed to support multiple windows running on one thread. Only use code like this if you really have to. You should never have to...


The main problem you ahve is that you do not establish a message pump in the new thread.

Check

Run multiple UI Threads

for a good overview how to run a high perforamnce user interface using multiple threads (one per form / group of forms).

What you basically miss is the call to Application.Run to set up the message pump on the separate UI thread.

I think once the last form of a message pump closes - it will dispose itself and end.

Note that all this ASSUMES you WANT to open the window in a separate UI thread... otherwise you need to invoke back to the main UI thread for the creation and all manipulation of the window, so it gets attached to the existing message pump. There are GOOD cases for both - one keeps thigns simple, the other allows a LOT more performance as every window has a separate message pump and can thus act individually - this is for example used a lot in trading applications which may need to update graphs on a number of screens and havea bottleneck if running single threaded in the UI.


As a rule of thumb you should avoid manipulating the UI from threads (creating a form is a sort of manipulation to the UI). You should always manipulate the UI from the main thread.


The form is closing because the thread has finished and is therefore free'd along with its resouces (the form). To make the thread stay running you need a loop

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....
    }
}

You'll need a method of setting IsOpen (like a timeout or a button) and obviously you'll need to actually create IsOpen as a property of the form and set it to true when the form is created.

I'll add here the same as other users... You should have a good reason for not using the main thread.


If it takes a while to prepare the data for the form, you can do that in a separate thread to keep the application responsive. When the data is ready you can return the object to the main thread an let it show it.

You should declare a variable for the object in the form rather than locally in the method, so that it survives when you exit the thread.

When you are ready to show the form, you can use the Invoke method to make a method call that will be executed in the main thread.


do not create and show forms in non-main thread. do it in main form thread.

Or do this:

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

but first version is better


Why are you creating a form on a new thread? There are times you need to use a new thread but other times you can use form.ShowDialog() on the main thread.


What about if you show the form as if it was a Dialog? You can use

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

This way the call will block until the myGraph form is closed. As you have the myGraph created on a separated thread calling the blocking ShowDialog should block only that thread.


Perhaps this is garbage collection:

After ThreadCreateCurvedGraph() exits, myGraph goes out of scope and closes.

You need to organise a way of the thread to hold on to the instance and wait (using a blocking wait) for it to close.

Edit: For instance add:

Application.Run(myGraph)

to the end of the method.
(See comments from TomTom)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜