6

I want to create multiple UI threads in my application. I have simulated the scenario as below. I am creating a new window / form on a button click in a background thread

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();
        }
    }  
}

Note that - I am doing IsBackground = true bacause when the user closes on the main form, the child forms/windows should also close down. Is there a more cleaner/graceful way to achieve the same ?

EDIT - I want to create dedicated UI threads for each window. I will have 10 such windows displaying real-time data in parallel.

Solution - Is this fine ? (as per msdn and Hans' comments below) have set the Apartment state (see code above)

protected override void OnClosed(EventArgs e)
{
    Application.Exit();
}
Angshuman Agarwal
  • 4,796
  • 7
  • 41
  • 89
  • Why don't you simple use a Background Worker? You shouldn't keep up forms you have displayed after your main application has been closed thats just messy. – Security Hound Sep 27 '11 at 11:35
  • Why do you even need another thread? Just create the form on the main thread and then call `f.Show()`. – svick Sep 27 '11 at 11:53
  • There is multiple ways around that. However, as @Ramhound already mentioned, you probably want to take a look at `BackgroundWorker`, because it have some nice events. - An alternative could be `Task`. – ebb Sep 27 '11 at 11:56
  • svick - I want to create dedicated UI threads for each window. I will have 10 such windows displaying real-time data in parallel. – Angshuman Agarwal Sep 27 '11 at 12:46
  • 2
    Pretty unusual to have a machine with 10 cpu cores. Calling Thread.SetApartmentState() is required. If you want to shut down cleanly then you'll have to store the forms in a List<> so that you can f.Invoke() a call to Application.Exit(). Displaying windows on multiple threads is almost never not a mistake. The windows have no Z-order relationship and arbitrarily disappear behind the window of another app. – Hans Passant Sep 27 '11 at 13:40
  • Thanks Hans. I did something like this - `protected override void OnClosed(EventArgs e) { Application.Exit(); }` Do I still have to store the forms in a list ? I think Application.Exit() will clear of the Message Pump anyways – Angshuman Agarwal Sep 27 '11 at 15:21
  • For secondary UI threads, you should call Application.ExitThread(), because Application.Exit will try to end all message loops and dispose all controls from all threads. Which will likely cause exception, because some of the controls belong to another thread. – Gman Feb 07 '13 at 13:35

3 Answers3

5

Messing with threads will only bite you sooner or later.

From MSDN:

Controls in Windows Forms are bound to a specific thread and are not thread safe. Therefore, if you are calling a control's method from a different thread, you must use one of the control's invoke methods to marshal the call to the proper thread

You can of course use as many threads as you like, but don't try to create a workaround to be able to use different threads for updating the UI. Use Invoke/InvokeRequired from your worker/background threads instead.

Using an extension method makes it cleaner: Automating the InvokeRequired code pattern

Community
  • 1
  • 1
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • My issue is closing the individual windows when the main form closes. So, what should I _Invoke_ from the worker thread (w.r.t. to my code above) when the main form closes ? Sorry, I am a bit confused. – Angshuman Agarwal Sep 27 '11 at 13:11
  • Those forms will get closed if you start handling threads the proper way (and not the solution in your question) – jgauffin Sep 27 '11 at 13:13
3

I think you will need to set the apartment state of your thread to single threaded as indicated here ApartmentState for dummies and here Thread-safe Form.Show: t.SetApartmentState(ApartmentState.STA). I don't know if that's possible on a background thread though.

Another thing that I would urge you to look at is MDI (multiple document interface, e.g. here). Do you really need different forms display as an own window or are they rather documents inside a common form? You may have of course a reason to create multiple UI threads.

Community
  • 1
  • 1
Andreas
  • 6,447
  • 2
  • 34
  • 46
0

You could handle the MainForm.Closing event and call subForm.Close ( marshalled onto the right thread ) for each sub form.

I'm not sure why you want the forms on separate threads, though. Can't you just display the sub forms non-modally on the main thread?

Nick Butler
  • 24,045
  • 4
  • 49
  • 70