In .NET 2.0 a feature was introduced so as to raise an exception if an application attempted to access a Windows Control on a thread other than the thread in which the control was initially rendered. This is because Windows Controls are deemed not thread safe, and only expect to interact with a single thread, and thus have no state lock protection. In 1.1 you could blissfully ignore this and most of the time your code would work..
The feature in 2.0 is disabled by default, but when you run under the debugger it is enabled. The debugging environment sets the static member on the Control class CheckForIllegalCrossThreadCalls to true.
Whenever you attempt to get hold of the underlying Windows handle for the control this static member is first inspected and if it evaluates to true the InvokeRequired method is invoked to see if you are indeed on the correct thread. If you are not on the correct thread the exception is thrown
The code below was generated by Reflector, taken from the base Control class
public IntPtr get_Handle()
{
if ((Control.checkForIllegalCrossThreadCalls && !Control.inCrossThreadSafeCall) && this.InvokeRequired)
{
throw new InvalidOperationException(SR.GetString("IllegalCrossThreadCall",
new object[] { this.Name }));
}
if (!this.IsHandleCreated)
{
this.CreateHandle();
}
return this.HandleInternal;
}
There is a slight extra piece of complication in that it is possible to have some control operations that are thread safe, these calls use a class called Control.MultithreadSafeCalllScope which implements IDisposable as a way to wrapup blocks of code that are in fact thread safe and still need to have access to the underlying windows handle.
So using Reflectors Analyze feature I decided to see where this class was used in the framework so that you can see what Windows control methods are Thread safe…
The results were as follows
System.Windows.Forms.Control.BeginInvoke(Delegate, Object[]) : IAsyncResult
System.Windows.Forms.Control.CreateGraphics() : Graphics
System.Windows.Forms.Control.EndInvoke(IAsyncResult) : Object
System.Windows.Forms.Control.get_InvokeRequired() : Boolean
System.Windows.Forms.Control.get_WindowText() : String
System.Windows.Forms.Control.Invalidate(Boolean) : Void
System.Windows.Forms.Control.Invalidate(Rectangle, Boolean) : Void
System.Windows.Forms.Control.Invalidate(Region, Boolean) : Void
System.Windows.Forms.Control.Invoke(Delegate, Object[]) : Object
A few posts back I saw that Invalidate was possible, but now I can see that I can also get the text associated with a windows control.
Anyway back to the plot….the reason for all this was to make my own custom controls behave the same as the underlying windows controls. I basically wanted to ensure that my control was only ever interacted with on a single thread. Since with UI apps you generally expect everything to happen on the main UI thread you don’t want to put the overhead of locking etc in as the majority of cases everything is happening on the UI thread.
So I’ve added a new method to my control called CheckForIllegalCrossCall I make a call to this method inside each of my properties..
private void CheckForIllegalCrossCall()
{
if ((Control.CheckForIllegalCrossThreadCalls) && (InvokeRequired))
{
throw new InvalidOperationException("Illegal cross Thread operation");
}
}
Now I don’t need to worry about state corruption as state can now only be manipulated on a single thread. When debugging we will make the call to InvokeRequired and when not we will simply assume that the programmer knows what he’s doing…
2 comments:
thanks man
Eralp,from Turkey
www.eralperat.com
Do you know the warhammer gold, In here you can buy the warhammer Online gold, Do you know that the warhammer money in the game is very important, If you had more cheap warhammer Online gold . I think you can get the tall level, quickly come here to buy warhammer gold.
Post a Comment