Threads, events and the GUI

I am a bit confused about how GUI can be used in multi-threaded applications.

I hear there is a thing called the UI thread. Which I assume is my main executing thread at the startup of the application.

I also hear (though I am not 100% on this) that doing UI stuff on other (non UI) threads is a very bad idea.

So, if I create a separate thread and I want to call MyForm myForm = new MyForm(); myForm.ShowDialog(); in it, what changes do I need to make for that to be "safe"?

Also, I have had some people tell me that events are spun out on a different thread. (Though I am not sure I believe this.) If they are, then I am confused. I can open a dialog (ie myForm.ShowDialog() in an event and nothing truly horrible happens. (Maybe this depends on if the event delegate was called with Invoke or BeginInvoke?)

Answers


Here are a few bits of info that may help you out. What you're saying about working with UI on non UI threads isn't just a bad idea, you'll get an exception. Meaning, if you create a Form in the main thread, and then spawn off a background thread to do some processing and then want to update the Form in that background thread, it'll throw an exception. In your example though, where you create the Form in a background thread, you should be OK. I'd question your design, but it won't blow up AS LONG AS YOU ONLY TOUCH THE UI IN THAT SAME THREAD.

As for events, events handlers are executed on the same thread they were raised on. Meaning, if you have a Form on one thread that spawns off some work on another thread that raises events, but before doing so, you hook into this event on the Form thread, you need to be careful not to touch the UI directly in the event handlers, because those event handlers are being called on the background thread.

Finally, the way to correctly manipulate the UI from a background thread, is by calling Invoke and passing in a delegate that does the UI work you want. HTH


In WinForms you need to call UI-things on UI thread, you always can check on what thread you currents are getting InvokeRequired of UI-control.

void ApplyUiChanges()
{
   if(this.InvokeRequired)
   {
       this.Invoke(new Action(ApplyUiChanges));
       return;
   } 

   // UI stuff here...
}

In WPF techinic is alike. But instead of using InvokeRequired you should ask CheckAccess() of DispatcherObject (All UI-controls derive from it)

void ApplyUiChanges()
{
   if (!dispatcherObject.CheckAccess())
   {     
      dispatcherObject.Dispatcher.Invoke(DispatcherPriority.Send, new Action(ApplyUiChanges));
      return;
   }
   // UI stuff here...
}

Also you can take a look at Async CTP, which might be useful. But it's only CTP, not a release yet.

Another way to handle UI-thread communication is to use PostSharp. Write (or copy-paste) GuiThreadAttribute. After that, you'll be able to use such semantics:

[GuiThread]
void ApplyUiChanges()
{
   // UI stuff here...
}

From what I've experienced, "UI thread" is a misnomer. There isn't one single thread that handles all of the UI for an application. To keep things simple, it's generally a good idea to have UI on one thread, but nothing stops you from spawning another thread, and creating new controls on that thread and showing them to the user. What's important is that control properties are only changed on the thread it was created on. As mentioned by another person, you can see if you are currently on that thread by looking at the Control.InvokeRequired property.

If you are on a thread that isn't the one you want a new form to run on and you don't have the luxury of being on the context of a control that is created on the thread you want, then you'll have to get a reference to the System.Threading.SynchronizationContext of the thread you want it to be on (I usually achieve this by storing a reference of System.Threading.SynchronizationContext.Current from the main thread in a static variable, but this can only be done after at least one control has been created on the thread). This object will allow you to run a delegate on its home thread.

I had to do this once in a Windows application that also hosted a WCF service, and UI needed to be launched from the service, but I wanted it on the same thread as the rest of the UI.

HTH, Brian


Need Your Help

How to Configure Visual Studio 2010 to run GEGL library?

c visual-studio-2010 gimp gegl

Using the tutorial of Compiling GIMP I have compiled GIMP, GEGL, Babl in windows. i had some errors, but those were on GIMP. i am not concerned about GIMP right now. i just want to use the GEGL lib...

remove part of a url with php

php url path relative

I've seen a lot of posts on this regarding values added to URLs, but not on the URL itself.

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.