views:

299

answers:

9

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!

A: 

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

Andrey
This is what he does.
TomTom
read carefully: "I use a thread that open it."
Andrey
Read his code. Problem: no message pump established. here are good reasons for having multiple UI threads´. Ever seen a single threaded trading applicaiton - they SUCK (hint: NinjaTrader - sucks for this).
TomTom
Do UI handling in single thread, and data processing in spawned. Following this pattern single threaded, multi form application will work great. My advice is correct and works.
Andrey
it does not always. Seriously. Look at high end trading applications - and low end "single threaded works" crap. Try using them. Well, you can not - probably never traded.
TomTom
Yes, i never traded. But i participated in development of investment app with rich ui and this pattern worked.
Andrey
A: 

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.

Darin Dimitrov
form creation is not exactly.... manipulation.
TomTom
If you think of Forms as just a part of the UI and not the container for the UI then it is.
dbemerlin
it still is wrong. There are great cases for multi UI threads.
TomTom
@TomTom: the answer starts off with *"As a rule of thumb [...]"*. That does not exclude that there are great cases, just that it should not be the first choice. As so often, the question lacks the essential information *why* the poster wishes to create the form on a thread; it may or may not be one of those cases where it is a good idea.
Fredrik Mörk
A: 

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.

Guffa
Not what the user asks. he is quite clear in the WANT to open the other window in a separate UI thread, which - incidentally - has sometimes REALLY good reasons (trading applications are well known for that).
TomTom
@TomTom: Please don't try to make a ruling about what the OP really wants. It's clear that a thread is currently used, but it's not clear that it's actually the desired solution. Just because the OP asks for something doesn't neccessarily mean that it's the correct solution. If one only ever aswered what was asked, a lot of questions couldn't be answered with anything other then "yes" or "no", as the question actually asked wasn't what was meant by asking the question.
Guffa
@Guffa - please dont try making a ruling about the OP really wants. Read his post. Follow his example and deduct what he tries to do. Dont assume the programmer is a rambling idiot.
TomTom
@TomTom: asking for the underlying reasons for the presented problem case is not the same as assuming the poster is an idiot. It simply helps in providing a better answer.
Fredrik Mörk
@TomTom: I have suggested a solution, that doesn't mean that I am trying to make a ruling about anything at all. I have read his post, and I have followed his example and deducted what he tries to do. Just because I don't come to the same conclusion as you do doesn't automatically mean that I am wrong, and it doesn't mean that I think that the OP is an idiot.
Guffa
A: 

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.

JamesB
So many people here dont really know the oncepts of multiple message pumps - it hurts. RTFM, guys. There are REALLY good reasons to do a multi threaded UI - I have one using up to 6 UI threads for 6 windows. Which all are busy repainting. This is fully supported.
TomTom
+1  A: 

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

Check

http://stackoverflow.com/questions/1566791/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.

TomTom
A: 

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)

quamrana
No, user needs to establish a MESSAGE PUMP to handle the windows messages of the new UI thread.
TomTom
@TomTom: Is that: `Application.Run(myGraph)` which would both hold onto the instance and wait for it to close?
quamrana
Exactly. It would establish a message pump and wait until the last window on it closes. This is similar to what happens in the main thread, which at start is not a UI hooked up thread either (which is why you read Application.Run there).
TomTom
A: 

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.

SoMoS
Not a solution and a total bypass of what is wrong.
TomTom
Great Idea! I think I'll do like u said.
menachem
As far as I know It works so I don't know why you are putting me negative votes.
SoMoS
It is called "unwanted side effects". Like a user asking how to tun off the computer and you tell him to hit it with a hammer -that also turns it off, but it has side effects. ShowDialog has those, too - if the user wants to start a UI in aseparate thread, this UI message pump should not be ni Dialog mode just because he got a bad advice.
TomTom
What side effects it has? I have not noticed any and I've used this approach for wait dialogs a long time.
SoMoS
+5  A: 

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

Hans Passant
Great except the last part - you should never have to. Ever seen a trading application that... does so many updates the UI falls behind on 6 screens ;) There is a need.
TomTom
@TomTom: I don't know why here is not wrong to put a ShowDialog here as I told.
SoMoS
A: 

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.

Michael