In the past week, I have been doing a few different things that explicitly or implicitly required me to deal with threading issues. Threading is a big scary topic to a lot of developers.
Visual Studio 2005 has a lot of asynchronous patterns built in (eg in the SqlCommand in ADO.NET, in web services) along with the BackgroundWorker Component which is there to assist us with the threading issue that the average windows programmer might encounter: UI cross-threading.
I previously wrote about VS2005's new sensitivity to cross-threading problems and have discovered some more about this over the past few days that I wanted to share.
The DoWork method of the BackgroundWorker component (and anything that DoWork calls) is being run in a background thread, not the UI's thread. What this means is that you need to avoid touching any of the UI controls in that code. You should only touch the UI controls (e.g. change properties) from the UI's thread. The BackgroundWorker component was created to make this challenge a little easier. When the process is finished, it sends a message back to another member of the BackgroundWorker, which is the RunWorkerCompleted event. It also includes any return values. The beauty of this is that the RunWorkerCompleted method has been designed so that it works in the UI's thread. The documentation also says that this method is thread safe. So when data comes back you can now do things like populate grids or text boxes.
(see Mike's comment below for an explanation of thread safety)
All of the samples I have seen in the documentation show us how we can now just change properties on the UI controls in the RunWorkerCompleted event.
So I was awfully confused when I kept getting an error in debug mode that said:
"Illegal cross-thread operation: Control 'myTextBox' accessed from a thread other than the thread it was created on."
when I was trying to change the Text property of that control (in RunworkerCompleted.)
The docs say of this warning: If you use multithreading in your Windows Forms applications, you must be careful to make calls to your controls in a thread-safe way. This exception is raised by the debugger and does not appear at run time, but you are strongly advised to fix this problem when you see it. For more information, see How to: Make Thread-Safe Calls to Windows Forms Controls.
I was in the UI thread, the async process was called from the UI thread, and my TextBox was created by the UI thread. Or so I thought. Look at what the Threads window shows me:

I looked at the threads when I was in the RunWorkerCompleted method and again when I was back in a form method (when I took the screenshot). The RunWorkerCompleted thread is #2036 and the form's main UI thread is 2892.
So what was going on? I spent a lot of time trying to figure this out and finally followed the prescription (see above link to How To: etc.) for doing this outside of the main thread, which is to use Invoke methods. It didn't occur to me to try this, since that was for working outside of the main thread - how logical - until I was encouraged by fellow ASPInsider Mike Campbell. Of course it worked.
But why? Is there something wrong with my code? With the component? Or with the docs? Or were the docs just written for normal scenarios? Had I done something so very unusual that it wasn't covered in the documentation? (I don't think I did anything unsual, by the way.)
If it's one of the last three, then that is worrisome. I'm fairly knowledgeable about .NET and I think I know about as much as I should about threading to make me not too dangerous (though perhaps not! :-)). Yet, following the MSDN documentation, I got myself into trouble - trouble that I couldn't figure out how to get myself out of. What about everyone else? The BackgroundWorker was specifically designed for people who don't know how to do asynchronous work, delegates or threading. So the target audience of this component will be highly likely to follow the docs. And probably won't have Mike Campbell advising them!
I still want to know what makes this an issue - why I am not getting back to the Main UI thread? If I find out, I will update.
There is a way to turn off this warning, though one wonders why you would want to do that!.