If you ever wrote something more, then standard UI input-output, you sure got into wide range of exceptions like “The calling thread cannot access this object because a different thread owns it” or “This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread”. What the problem? The problem is old like condom in my wallet world-old, the try to get into resources from different threads. Let me show you some code. Very-very bad code. It’s unbelievable, that this code can ever work.
Let’s write Thread Safe Observable Collection, that knows, that it might be called from big number of threads and take care on itself. Sounds good? Let’s start.
First of all we’ll try to get current STAThread (UI) dispatcher. How to do it? Simple. The only place we’ll initialize our collection is in XAML, so default constructor will be called from the thread we need. Now, we save it
Dispatcher _dispatcher;
public ThreadSafeObservableCollection()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
The next step is to override all vital methods of our collection to be invoked from this thread.
protected override void ClearItems()
{
if (_dispatcher.CheckAccess())
{
base.ClearItems();
}
else
{
_dispatcher.Invoke(DispatcherPriority.DataBind, (SendOrPostCallback)delegate { Clear(); });
}
}
Let’s understand it. First we’re checking if the current thread can access the instance of the object, if it can – we’ll just do our work, but if not, we’ll invoke it in the context of the current thread by sending anonymous delegate with or without parameters.
Why I’m casting the anonymous delegate into SendOrPostCallback? The answer is simple – look into Reflector. You can not implement your delegate with parameter and without return value better
Read more: Tamir Khason – Just code
0 comments:
Post a Comment