Introduction
My little list is an improvement of the ObservableCollection<T>
to handle multithreading. And (that is the clue) just do the event handlers from the foreground thread in the foreground thread. This results in a great boost of performance for me.
Background
My first approach was to give my collection a Dispatcher to invoke the CollectionChanged
events. This resulted in some performance problems because I do some searching in my own handlers. With the new list, only the WPF handlers are done in the foreground thread, which is of course much faster.
Using the Code
You can use my collection as a normal Observed Collection. I still have some synchronization issues because Microsoft does not use a thread safe enumeration. If anyone has a clue as to how we can improve this, please tell me.
Here is the tricky part of the collection:
public override event NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
{
foreach (Delegate del in CollectionChanged.GetInvocationList())
{
PropertyInfo prop = del.Target.GetType().GetProperty("Dispatcher");
if (prop != null)
{
(prop.GetValue(del.Target, null)
as Dispatcher).BeginInvoke(del, this, e);
}
else
{
del.DynamicInvoke(this, e);
}
}
}
}
Advanced Thread Safety
Because Microsoft does not care about checking the CollectionChangedEvents
, I needed to do it on my own. This will happen before I tracked the operations posted to the WPF Dispatcher:
- Lock the list (this prevents the Dispatcher from processing the events you post)
- Add an item
- Remove the item again
- Release the lock on the list (the Dispatcher is now able to Update)
- The Dispatcher tries to access the element at index 1 from step 2, and crashes because at this time the item is not in the list
I modified the OnCollectionChanged
of the Collection to track down the Operations that I get from DispatcherInstance.BeginInvoke
. So on each event, I first check the previous Operations and if they interfere with the actual action. When an Operation is completed, I remove it from the tracking. This is not completely functional at the moment, so if you try my collection please give me some feedback as to how the handling can be improved. So this is how it's going now:
- Lock the list
- Add an item
- Remove the item again
- Detect that the operations from step 2 and 3 remove each other and cancel both
- Release the lock
- The Dispatcher is fine
History
- 15 Mar 2009: Initial version
- 19 Mar 2009: Added thread safety extensions