Posts
58
Comments
403
Trackbacks
0
Have worker thread update ObservableCollection that is bound to a ListCollectionView

While playing around with WPF, I tried to do some multithreading where I have a worker thread updating my ObservableCollection, while having a ListCollectionView of that ObservableCollection being shown on a ListBox.

It was surprising to see that I get a NotSupportedException thrown, with the message saying 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.'.  That doesn't seem to make sense - In my mind, I understand how the thread that created the UI should be the one that handles all UI updates.  However, the data itself should be able to reside anywhere, and I should be able to update it however and whenever I want.

Looking for a solution, I created a class deriving from ObservableCollection (the class name I chose is ObservableCollectionEx) thinking that I would just manually walk through the event's invocation list.  Well, that didn't quite work, since events are not accessible (other than for adding/removing delegates) to child classes.  Looking at the documentation, the CollectionChanged event in ObservableCollection is virtual - that means I can override it! Yeah!  I am glad someone at Microsoft decided to make that virtual.

So here's the code that I created - the pain is I now have to rename all occurrences of ObservableCollection to this new class.  Oh well, at least making it work with threads isn't too painful. 

public class ObservableCollectionEx<T> : ObservableCollection<T>
{
   // Override the event so this class can access it
   public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;

   protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
   {
      // Be nice - use BlockReentrancy like MSDN said
      using (BlockReentrancy())
      {
         System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
         if (eventHandler == null)
            return;
    
         Delegate[] delegates = eventHandler.GetInvocationList();
         // Walk thru invocation list
         foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
         {
            DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
            // If the subscriber is a DispatcherObject and different thread
            if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
            {
               // Invoke handler in the target dispatcher's thread
               dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
            }
            else // Execute handler as is
               handler(this, e);
         }
      }
   }
}

 Update:

There is a bug with the code where subscribers in the same thread won't get called - the code above has been updated with the fix.

 

It also uses CheckAccess (available, but not shown via Intellisense as mentioned here).

posted on Wednesday, January 16, 2008 6:30 PM Print
Comments
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Kevin Kerr
1/23/2008 10:30 AM
Nice job! This has been attempted several times by others. In case you are interested, here are some links to others:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2617169&SiteID=1

and here is a link my my solution:
http://blog.quantumbitdesigns.com/2008/01/06/wpf-cross-thread-collection-binding-part-4-the-grand-solution/

Keep up the good work!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Jake
5/12/2008 5:06 PM
I'm trying the code you posted and I'm getting the following error.

Code:
System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;

Compile Error:
The event 'System.Collections.ObjectModel.ObservableCollection<T>.CollectionChanged' can only appear on the left hand side of += or -=

Any ideas?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
SeveQ
9/21/2008 5:39 AM
Same issue here... Anything new about it?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Muljadi Budiman
9/22/2008 8:48 AM
The event has to be overridden first (4th paragraph). You can override it by:
public override NotifyCollectionChangedEventHandler CollectionChanged;
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Muljadi Budiman
9/24/2008 9:13 AM
Should've had the event keyword there:
public override event NotifyCollectionChangedEventHandler CollectionChanged;
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
SeveQ
9/24/2008 10:20 AM
Okay, thank you. I've already found something thet helps me with this problem. It's very similar to your solution.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Sabrina
12/16/2008 12:17 PM
Good job, been looking around for solution and this works for my problem very well.Most of solution requires the Dispatcher, and I dont want/have access to Dispacther as the collection is deep in the business layer. Getting Dispatcher from the handler is just brilliant!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
DeanS
4/7/2009 6:30 PM
Well done. Walking the InvocationList is genius.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
derm2
6/11/2009 1:51 PM
This solution has an issue, but it's only really apparent with multicore processors and large collections. I got this 5% of the time with a list of 4000.

Wpf code may throw indexoutofranceexceptions when removing items asynchronously. External code may try to access ony of the last items after they were removed from the collection, but before the invoke happens. Raising the priority to 'Send' didn't solve this either. The async code was still sitting in invoke when the exception was thrown.

I'll try to go the hard way and get most of the collection's functions invoke themselves when not on the UI thread.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Sven
8/12/2009 4:28 AM
The comment "I don't want/have access to Dispatcher as the collection is deep in the business layer" is a bit misleading. In WPF, all objects have access to Dispatcher. The trick is to get the one for the main thread - I get a reference to the current Dispatcher in my constructor, which (in my specific example) is always being called on the main thread. I've been very successful doing what derm2 suggests, and invoking as appropriate.
Gravatar
# Comment for derm2
Muljadi Budiman
8/14/2009 5:38 AM
Unfortunately external code trying to access some of them items after they're removed is a general problem with multi-threading. A resource that can be accessed by multiple threads need to have locks before it is accessed.

Consider a single list (regular one, not even ObservableCollection) and code that will add an item to the list if the list doesn't contain the item. If the code is then run in parallel on multiple threads (on multi-core CPUs) but the code doesn't lock the list, it will have multiple same items added to the list.

You're correct that Dispatcher adds a level of complexity since the handler execution is not direct (it is added to the Dispatcher Queue); however to depend on the event not firing to assume an item hasn't been removed sounds dangerous too.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Vijay
8/24/2009 5:31 AM
It is a smart solution. Helped me on time. Thank you very much.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
TC
12/16/2009 2:41 AM
Maybe I'm missing someting, but putting this into my code causes a "Does not exist in current context" error on the using(BlockReentrancy()), CollectionChanged and Dispatcher(Object|Priority) lines?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Muljadi Budiman
12/18/2009 4:25 AM
The code snippet provided is just the method that does the heavy work. However, most people ended up copying and pasting the code without reading the post in depth.

The solution offered assumes that the code will be pasted within a class that derives from ObservableCollection<T>; to alleviate this assumption, I've updated the code to reflect the whole class - along with the code that overrides the event.

Hopefully this makes it clearer to people that read this post.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Nelson Reis
12/30/2009 3:16 AM
That's a great solution! Thanks!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Anthony Paul Ortiz
3/12/2010 1:19 PM
It would seem that great minds think alike! :D

http://www.codeproject.com/KB/dotnet/MTObservableCollection.aspx
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
s. singh
3/18/2010 7:15 AM
Thanks a ton! I've been bash'n my head on my desk trying to get my solution to work--now I'm just using yours :)
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
aziz
6/15/2010 8:25 PM
you are cool and solved my issue :)
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Stephen
6/17/2010 5:47 AM
This solution works great for WPF, but in Silverlight you can't override the CollectionChanged event. Any ideas for how I can get around that in Silverlight?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Ojas
6/23/2010 8:09 PM
Nice work
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
jefftoaster
8/3/2010 11:19 AM
Awesome - thanks so much!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Plague
8/16/2010 9:00 PM
Cool - solved my issue perfectly!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Gustavo Cavalcanti
8/17/2010 8:02 AM
Very nice! Thank you so much.
Gravatar
# frequent use
Csaba
8/31/2010 7:07 AM
It is indeed a nice solution.
However when i quickly add two items to the list, sometimes it adds two times the second item. I understand the reason but i dont really know how it can be solved. Can someone help me?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Steven
10/10/2010 8:49 AM
Great solution for WPF, unfortunately doesn't work for WP7, since you cannot override the CollectionChanged event there. So annoying that they've made these small but IMPORTANT changes to the framework for WP7. Well, have to find another solution :)
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Nick
1/2/2011 7:50 PM
I had the same problem, but found a different solution which was satisfactory for my problem and wanted to share it:

I created a temporary collection to store the results during processing on the Worker Thread. Once the Worker Thread completed executing, I copied the temporary collection to the ObservableCollection to which was Bound to a ComboBox.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
5 in 1 reflectors
2/2/2011 9:09 PM
I wanted to thank you for this excellent read!! I definitely loved every little bit of it.Cheers for the info!!!! & This is the perfect blog for anyone who wants to know about this topic. You know so much its almost hard to argue with you .........
thanks
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Genital Warts Treatment
2/14/2011 10:10 PM
This is probably one of the best mentions of this topic I've seen in quite a while. It's obvious that your knowledge of the subject is deep and this made for a very interesting read.
Gravatar
# Airsoft Guns
Airsoft
2/15/2011 1:25 AM
Been a reader for some time now, just wanted to say thanks for the great blog and hope you have a wonderful new year to come.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
syler
2/19/2011 1:21 AM
thanks, it works, you've saved my time
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
foot pain
3/2/2011 9:40 PM
Hi, I found your post really helpful. It helped me all the way in completing my assignment, I am also giving a reference link of your blog in my case study. Thanks for posting such informative content. Keep posting.
Gravatar
# Works Great Except When ...
OT
3/3/2011 10:59 PM
Hello and thanks for you great implementation...

The only problem im experiencing is that after updating my ObservableCollection from the UI, i cant delete items anymore from a different thread...

Any Ideas Please?

Thanks Alot
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
buy steroids online
3/6/2011 7:52 PM
What I dont understand is how you are not even more popular than you are now. You are just so intelligent. You know so much about this subject, made me think about it from so many different angles. Your stuffs great. Keep it up..
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Pinakin Shah
3/7/2011 7:40 AM
Thank You. It saved saved my time and learned something.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
stretch carpet
3/12/2011 3:59 AM
This blog gives the light in which I can observe the reality. This is very nice one and gives useful information. Thanks for this nice blog.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
kickspace heaters
3/18/2011 6:39 PM
A fantastic presentation. Very open and informative.You have beautifully presented your thought in this blog post
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
accredited online degrees
3/22/2011 9:53 AM
This is a really good post. Must admit that you are amongst the best bloggers I have read. Thanks for posting this informative article.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Peter
3/29/2011 7:53 AM
Thank you for a great post. The ObservableCollectionEx is working very well for us. However, we cannot seem to use it Telerik RadGridView. We get the same exception as if we were still use ObservableCollection.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Idan
5/1/2011 2:33 AM
works great! thanks
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Ramius
6/8/2011 8:06 PM
Very nice, works like a charm!! Strange that Microsoft havn't added this to the collection
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Mike
6/26/2011 3:42 PM
Hey thanks for posting this. Even though this post is old. It helped rectify a problem I was having in WPF when subscribing to an IObservable collection from a service. VS2010 would crash without using this method of dispatcher handling.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Cris
6/27/2011 12:08 AM
I have to really thank you very much, you've solved me a weird problem !!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
F£ö
7/13/2011 5:26 AM
Thanks a lot for that brilliant piece of code !! It helped.
By the way, you forget the 3 constructors override, but it does not really matters, does it.
Great job.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Juri Skuratovski
7/14/2011 2:42 AM
Great solution!
Works like a charm for me!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Chris
12/8/2011 4:54 AM
Thanks. This code helped me
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
M
12/13/2011 9:12 AM
Thanks. It works!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Windows Hosting India
12/20/2011 5:17 PM
This is a nice blog regarding the health topic which is the most essential thing for everyone. I have read the whole blog and the information provided here are nice and true which should be keep in our mind.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Mattias
12/28/2011 5:26 AM
Thanks mate! This really helped me.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Luca
1/15/2012 6:42 AM
Thanks it works. I really appreciate
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Clifford Nelson
6/29/2012 5:14 AM
Fixed my problem. Wish I understood what you did. Added another contructor for IEnumberabl<T>, don't know why you did not.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
eBot
7/16/2012 7:13 AM
Finally something that works for this issue. Have tried several other posts with no success as my situation was rather unique. Thank you!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Engin
8/1/2012 12:50 AM
Thanks. I have tried some other solutions but this code completely solves my problem. Thanks again.
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
RG
1/11/2013 4:22 AM
Any chance of a VB version: failing miserably to translate the damned event :(.

LOL
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
RG
1/11/2013 5:01 AM
I think I got it :). Had to use a sub lambda.
Public Class ObservableCollectionEx(Of T)
Inherits ObservableCollection(Of T)

' Override the event so this class can access it
Public Shadows Event CollectionChanged As System.Collections.Specialized.NotifyCollectionChangedEventHandler

Protected Overrides Sub OnCollectionChanged(ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
' Be nice - use BlockReentrancy like MSDN said
BlockReentrancy()

Dim eventHandler As System.Collections.Specialized.NotifyCollectionChangedEventHandler = Sub() RaiseEvent CollectionChanged(Me, e)
If (eventHandler Is Nothing) Then Return

Dim delegates() As [Delegate] = eventHandler.GetInvocationList
' Walk thru invocation list
For Each handler As System.Collections.Specialized.NotifyCollectionChangedEventHandler In delegates
Dim dispatcherObject As DispatcherObject = CType(handler.Target, DispatcherObject)
' If the subscriber is a DispatcherObject and different thread
If ((Not (dispatcherObject) Is Nothing) _
AndAlso (dispatcherObject.CheckAccess = False)) Then
' Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, Me, e)
Else
handler(Me, e)
End If
Next
End Sub
End Class
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
tetris
2/24/2013 2:33 AM
It doesn't work.. im using threadpool to update the collection and im getting error:

"Added item does not appear at given index"

any body have an idea? i've search google to no avail...
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
John Woodard
3/13/2013 5:25 AM
Found an issue where doing an Add followed by a Remove(0) (to make the collection circular at a give size) can on some machines cause an exception. I don't have the exception text handy, but it comes from the XAML side and it complains about the number of items in the collection being inconsistent, which makes it seem like the UI updates are happening between the Add and Remove(0)
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Brannon
5/7/2013 10:16 AM
I have the exception text:

System.InvalidOperationException: An ItemsControl is inconsistent with its items source.
See the inner exception for more information. ---> System.Exception: Information for developers (use Text Visualizer to read this):
This exception was thrown because the generator for control 'System.Windows.Controls.ListBox Items.Count:429' with name '(unnamed)' has received sequence of CollectionChanged events that do not agree with the current state of the Items collection. The following differences were detected:
Accumulated count 428 is different from actual count 429. [Accumulated count is (Count at last Reset + #Adds - #Removes since last Reset).]
At index 1: Generator's item '16:02:54.706, Error, Title: Too far from segment start, Message: dist: 53.586 segstart:(-221.311,806.222) pose:(-166.656,807.233), Sender: Spooler (65), Removed: 16:02:59.681, Notification Cleared ' is different from actual item '16:04:02.557, Error, Title: Off Path, Message: d: 10.8, Sender: Spooler (65), Notification Added'.
At index 2: Generator's item '16:02:54.671, Error, Title: Off Path, Message: d: 10.8, Sender: Spooler (65), Removed: 16:02:59.661, Notification Cleared ' is different from actual item '16:02:54.706, Error, Title: Too far from segment start, Message: dist: 53.586 segstart:(-221.311,806.222) pose:(-166.656,807.233), Sender: Spooler (65), Removed: 16:02:59.681, Notification Cleared '.
At index 3: Generator's item '16:02:43.816, Error, Title: Too far from segment start, Message: dist: 53.586 segstart:(-221.311,806.222) pose:(-166.656,807.233), Sender: Spooler (65), Removed: 16:02:48.751, Notification Cleared ' is different from actual item '16:02:54.671, Error, Title: Off Path, Message: d: 10.8, Sender: Spooler (65), Removed: 16:02:59.661, Notification Cleared '.
(... 86 more instances ...)

One or more of the following sources may have raised the wrong events:
System.Windows.Controls.ItemContainerGenerator
System.Windows.Controls.ItemCollection
System.Windows.Data.ListCollectionView
* Asi.Ui.Wpf.CrossThreadObservableCollection`1[[Asi.Notifications.Notification, Asi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
(The starred sources are considered more likely to be the cause of the problem.)

The most common causes are (a) changing the collection or its Count without raising a corresponding event, and (b) raising an event with an incorrect index or item parameter.

Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
tetres
6/12/2013 3:03 AM
@Brannon, Im getting that exact issue "An ItemsControl is inconsistent with its items source." but this only happens after i installed vs2012 it was already working correctly using vs 2008 anyone found the solution?
Gravatar
# An ItemsControl is inconsistent with its itemssource.
bajwa
12/24/2013 10:13 PM
@Brannon @tetres

i am getting the same issue. Has anyone been able to resolve this?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
bajwa
12/24/2013 10:30 PM
i think i've zeroed into the problem (atleast when i repeat this, the problem surfaces, hence it is now in predictable domain).

The problem arises while the collection (which is binded to a listbox) is being updated from a background thread and the view is refreshed (window is maximized, dimensions change).

This causes an exception while redrawing because while the redraw function (in the UI Thread) is measuring the screen real estate required by the children, the child count changes (because it is also being updated in a background thread). This causes the exception ("An ItemsControl is inconsistent with its items source.") to be raised. i was able to come up with this theory by looking at the stack trace.

Now, the big question: how can i prevent this? Locks?
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Anitha
1/21/2014 5:06 AM
Thanks a ton for sharing. You made my day!!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Anitha
1/21/2014 5:06 AM
Thanks a ton for sharing. You made my day!!
Gravatar
# re: Have worker thread update ObservableCollection that is bound to a ListCollectionView
Zberbang
6/5/2014 12:22 AM
To bajwa and others.
There is workaround the problem.
Bind ItemsSource to ICollectionView with sorting or filtering enabled.

It works:
view.Filter = o => true;
view.SortDescriptions.Add(new SortDescription());

Post Comment

Title *
Name *
Email
Comment *