views:

258

answers:

2

Update: here is an MSDN article How to: Make Thread-Safe Calls to Windows Forms Controls. It states:

The .NET Framework helps you detect when you are accessing your controls in a manner that is not thread safe. When you are running your application in the debugger, and a thread other than the one which created a control tries to call that control, the debugger raises an InvalidOperationException with the message, "Control control name accessed from a thread other than the thread it was created on."

This exception occurs reliably during debugging and, under some circumstances, at run time.

My previous experience was that the exception was thrown at run time, too.

Thanks to Spence for pointing me in the right direction.


I have a pretty common error in WinForms app: background thread accessing UI controls directly instead of using Control.BeginInvoke().

My problem is the following: I see the InvalidOperationException "Cross-thread operation not valid: Control 'uxCheckStatus' accessed from a thread other than the thread it was created on." in debugger on background thread, but then it is swallowed somewhere in WinForms internals.

I expect it to kill the background thread and entire application.

Moreover, the code that is triggering it uxCheckStatus.Text = "success"; sometimes gets executed during/after exception is thrown i.e. label text reads 'success'! I'm basically lost. Anyone else experiencing this behavior?

I reproduce it on completely new WinForms solution with 1 button, both using ThreadPool and Thread for evil background thread.

If I throw a new InvalidOperationException() on background thread, it does kill the application. So my only guess is that WinForms handles this specific exception somewhere, but I cannot find references to this behavior on the web.

I run .NET 3.5, VS 2008.

A: 

I don't know of any specific documentation for how/why WinForms handles this exception. However, if you want to gracefully shut down your application when this happens, consider a global exception handler.

Eric J.
Application.ThreadException is not invoked. AppDomain.CurrentDomain.UnhandledException is and theoretically I can shut down app from it.
Alexander Abramov
+2  A: 

THis is by design. This is a coding error, not a runtime error. THe developers of Winforms decided that from .Net 2, they would implement code to check for the cross thread code and then fire an MDA. The MDA isn't an exception though, it's a check for badly designed code.

Additionally the MDA doesn't fire when your code is in release mode, it will just randomly fail every so often, the MDA is to help you at test, not during release.

I'm assuming that you are rewriting a badly written application to invoke onto the threads and you were hoping that the exceptions would catch for you, I have a suggestion:

Update your event handlers for GUI stuff to look like so:

public void button_clicked_handler(object sender, EventArgs e)
{
   if(this.InvokeRequired)
{   
   this.Invoke(delegateToThisMethod)
}
else
{
   //perform method
}

This pattern will catch all your methods and make it seamless for cross thread ops. If the threads are directly accessing code, this is a little tougher. You can get around this by renaming a control, then creating a property to the control, where you can then apply the invoke pattern to it. I've had to do this to troubleshoot some very funky cross thread stuff before.

Good luck ;)

Spence
What is 'MDA'? And do you have any references to 'by design'? Let me repeat myself: I know that I should use 'Control.BeginInvoke'. And I think that when I forget to use it application should 'fail fast', not swallow the exception.
Alexander Abramov
Ok, after you mentioned debug mode, I found reference to it on MSDN, thank you.
Alexander Abramov
I knew it was buried somewhere in MSDN. Well done for putting the info into the question, lots of people don't realise that SO is designed as a repository of useful answers, maintenance like that is what makes this site great. Good luck with your debugging, nothing like reading someone elses code :)
Spence
MDA: Managed Debugging Assistant. MDA's are things which notify you when something bad has happened in terms of code whilst the debgugger is attached, but will not happen in release mode. Basically they instrument .Net and fire when you did something you shouldn't.
Spence