WPF Window Exercise

I had a situation here where I was trying to figure out how to create a WPF window from a console application. I couldn’t use the application class, and found it to be a nice little exercise. As it’s an extremely rare case, I don’t expect it to be useful again, but I found it interesting, and decided to document it, and write it here. Enjoy.

Here we have a WPF prompt to be opened in the normal flow of a program.


var prompt = new SettingsWindow();
prompt.Show();

We run this, and we are hit with an exception.

The calling thread must be STA, because many UI components require this.

Here we can see that our thread must be a STA thread, or a single threaded apartment thread. Any thread that hosts Windows Forms must be a STA thread, because some components require it to work properly. Normally, when you create a WPF project, this is taken care of for you, but since this thread wasn’t created for the purpose of hosting a windows form, we must create one that is. To get this working, let’s make a background STA thread.


var staThread = new Thread(() => {
var prompt = new SettingsWindow();
prompt.Show();
)} { IsBackground = true };
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();

If we run this again, we now get through without an exception, but our window opens, and then closes right away. This is obviously not what we want. We can use another method of the Window class called ShowDialog() that should keep this window open.


var staThread = new Thread(() => {
var prompt = new SettingsWindow();
prompt.ShowDialog();
)} { IsBackground = true };
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();

This seems to work great. Although if you play around with this a bit, you’ll notice that this does not act like a background thread completely, and could keep your application running depending on how your application is terminated.

By changing the method back to Show, and running the Dispatcher, we can make this run more like we expect it to. Let’s take a look at the changes.


var staThread = new Thread(() => {
var prompt = new SettingsWindow();
prompt.Show();
System.Windows.Threading.Dispatcher.Run();
)} { IsBackground = true };
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();

This is what we want to see. One last change we want to make is now that the dispatcher is running, we want to make sure that it terminates along with its window, and we’ll use the closed event to do it. Let’s look at our final iteration of the snippet.


var staThread = new Thread(() => {
var prompt = new SettingsWindow();
prompt.Closed += (s, e) =>
prompt.Dispatcher.InvokeShutdown();
prompt.Show();
System.Windows.Threading.Dispatcher.Run();
)} { IsBackground = true };
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();

Now, we have a backgroud single-threaded apartment thread that hosts a WPF window that works just how we expect it.

Author: Peter

Thank you for visiting my profile. I encourage you to get in contact with me, and follow me on GitHub : https://github.com/emancipatedMind. I look forward to collaborating with you.

Leave a Reply

Your email address will not be published. Required fields are marked *