What is a UI thread? Is there only one UI thread in a .NET application?
views:
167answers:
3EDITED for correctness:
There is one UI thread per active APPLICATION in Windows Forms and similar concept for WPF.
ie: When you start the app, there is one thread, it becomes a UI thread when Application.Run(new Form1()); is called.
If you try to do Application.Run(new Form2()); at runtime you will get "System.InvalidOperationException: Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead."
If you really needed two seperate forms to not share the same thread, you would need to create a new thread, then call Application.Run(new MyForm()) etc etc. This is not common.
(Simplification ahead)
A UI thread is a Single Threading Apartment thread that is used to create various user interface objects (in Winforms, this means Controls). By convention and rule, a Control may only be accessed from within the thread that was used to create it; doing otherwise can and will produce unexpected results, from visual oddities all the way to a crash.
Unless you explicitly create more, there is only one UI thread within a Windows Forms application. While you can create another thread and start a message loop, there are very few reasons why you'd want to do this, and two different UI threads cannot "talk" to each other any more than any other thread can talk to a UI thread.
A UI thread has a number of characteristics that make it special:
- Windows has a message queue associated with the thread. This happens as soon as the very first window gets created on the thread.
- The thread runs a message loop, allowing Windows to dispatch messages to the windows. The message loop gets created as soon as you call Application.Run().
- COM was initialized on the thread, requesting a single-threaded apartment. An STA is necessary to allow many Windows features to work properly, features that are not thread-safe by design. COM ensures that these features are always called in a thread-safe manner, marshaling the call from a worker thread to the STA thread as needed. Examples of these features are Drag+Drop, the clipboard, the shell dialogs (OpenFileDialog etc).
- The thread never blocks on any operation, it stays responsive so it can dispatch Windows messages as required to keep the user interface responsive and COM marshaling requests flowing. Making calls to WaitHandle.WaitAny() for example are explicitly forbidden and generate an exception.
The startup thread of a process is almost always selected as the UI thread, although that's not a hard requirement. The STA state is selected by the [STAThread] attribute on the Main() method.
You can create another UI thread by ensuring that the above requirements are met. That could look like this in a boilerplate WF app:
private void button1_Click(object sender, EventArgs e) {
var ui = new Thread(() => { Application.Run(new Form2()); });
ui.SetApartmentState(ApartmentState.STA);
ui.Start();
}
That creates a second window, running on its own UI thread. Note that closing the startup form doesn't terminate the app. One typical problem you have with this arrangement is that you've now got two separate windows, they are not associated with each other at all. The 2nd window cannot be owned by the 1st, it has its own Z-order independent of the 1st. Difficult to deal with by the user. Except in rare circumstances, this doesn't improve the user interface at all.