Posts
58
Comments
403
Trackbacks
0
ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items

One issue with an app I'm developing is speed.  It's a WPF desktop app, and it has a global list of entities being loaded, and we're using ListCollectionView to show the entities (filtered accordingly by each ListCollectionView created).  We always thought that it was a DB issue, so yesterday I went researching how to optimize the DB call & code in general.

My code was very spartan; paraphrasing, it goes as follows:

BaseEntity[] entities = GetEntities(parentId);

foreach (BaseEntity entity in entities)

{

   ProcessEntity(entity);

   GlobalList.Add(entity);

}

GlobalList is a KeyedCollection derived-class that implements INotifyCollectionChanged.  The GetEntities method hits the DB and reads some 3000+ records, instantiating an entity for each record.  This whole 6 liner takes 20+ seconds.  When I profile this, the DB call took 200+ ms; the GlobalList.Add took almost 20 seconds by itself.  I was piqued by this, and went deeper.

For each item being added to the list, the class raises the CollectionChanged event.  And there were 45 ListCollectionView that is created from this GlobalList; hence each of them become subscribers of that event.  Doing the math, with over 3000 items being added, the event raising results in over 150000 delegate calls - which is why it took almost 20 seconds to do.

Since we created the code for the this GlobalList class, I added an AddRange method, which will accept IList<BaseEntity> as its parameter which will then just raise the event once by calling OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items)); passing in the items as the parameter to the event argument.

Piece of cake, right?  It turns out that ListCollectionView will throw a NotSupportedException saying that range actions are not supported.  CollectionView behaves the same way too.  The easiest solution, and it makes sense too, and it is NOT supported - I was blown out of my mind.

The second solution I tried was to just raise the event once, passing the last item being added as the event argument.  No dice; the ListCollectionView will only show 1 additional item (instead of the 3000+ items being added).

The solution I came up with is to then still use the AddRange method, and in the OnCollectionChanged method iterate through the invocation list of the event, and if the target is a CollectionView then do not call the handler, but call its Refresh method (which will recreate the view).  Code follows:

protected virtual void OnCollectionChangedMultiItem(NotifyCollectionChangedEventArgs e)

{

   NotifyCollectionChangedEventHandler handlers = this.CollectionChanged;

   if (handlers != null)

   {

      foreach (NotifyCollectionChangedEventHandler handler in handlers.GetInvocationList())

      {

         if (handler.Target is CollectionView)

            ((CollectionView)handler.Target).Refresh();

         else

            handler(this, e);

      }

   }

}

Result? Our loading code went from 27 seconds to 5 seconds.

Moral of the story?  Coming from my C++ background, I got used to properly delete items, counting references, and making sure things get cleaned up when possible.  C# espouses faster application development, it's more intuitive, better IDE, and given its automatic garbage collection, we sometimes forget to that we still have to manage stuff under the hood where necessary.  Better understanding of how things work under the hood is still key to creating fast performing, efficient code, even if you can't look at the source for the code.

Please note that the above code works well when you add multiple items - when you're adding items one by one (or you're forced to, can't add in bulk), you'll still get the same slowdown.  Another way to solve this is to have a public property on the collection class (say DeferCollectionChangedEvent); when it's set to true, then you will just accumulate the items and then raise the event whenever DeferCollectionChangedEvent gets reset to false (or provide a function that can trigger the CollectionChanged event).

Hopefully this may become useful to those trying to use WPF & uses CollectionView extensively.

posted on Wednesday, January 16, 2008 9:33 AM Print
Comments
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Klaus
2/24/2009 9:47 AM
Wonderful stuff. Just ran into exactly the same issue and ran across your post. Thank you very much.same problem. I have a
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Thomas Levesque
11/26/2009 12:15 PM
An easier solution would be to use the DeferRefresh method of the ICollectionView :

ICollectionView view = CollectionViewSource.GetDefaultView(collection);
using (var disposable = view.DeferRefresh())
{
// Add multiple items to collection
}
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Muljadi Budiman
12/1/2009 9:40 AM
Hi Thomas.

Thank you for your proposed solution; however it does not quite solve this particular situation that I happen to encounter.

In my 4th text paragraph (not counting the code excerpt), I mentioned that the GlobalList is already tied to 45 CollectionViews. The code that handles updating the collection doesn't know what collection views is tied to it (other than walking through the CollectionChanged event invocation list).

I am aware of DeferRefresh; it also still doesn't solve the event from the collection being fired once for each item addition. IMHO, having ICollectionView CollectionChanged event handler be able to handle multiple items additions/removal would be the ideal solution.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Mathias
1/7/2010 1:18 AM
The line NotifyCollectionChangedEventHandler handlers = this.CollectionChanged; doesn't compile. It sais "The event 'CollectionChanged' can only appear on the left hand side of += or -=.
Can you provide the full working source code?
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Fatih Sahin
1/11/2010 11:50 PM
Thank you very much. This helped me a lot, because debugging through these kind of bugs is a nightmare. You saved my life!
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Muljadi Budiman
1/12/2010 3:48 AM
Replying to Mathias:

The post was written to illustrate the performance issue and my workaround, which when I look at it now doesn't quite convey everything on how I did it. If you read everything, then it makes sense, but you have to piece a lot of things together - my apologies.

I've written a new post (http://geekswithblogs.net/NewThingsILearned/archive/2010/01/12/make-keyedcollectionlttkey-titemgt-to-work-properly-with-wpf-data-binding.aspx) on using the KeyedCollection class that does the same thing, hopefully this can be more useful to you.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Shimmy
2/1/2010 5:15 AM
Be sure that this is not fixed for .NET 4, I promise you.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Shimmy
2/1/2010 6:38 AM
I am having a hard time to get the NotifyCollectionChangedEventHandler handlers = this.CollectionChanged; line translated to vb.net, can anyone help me out please?
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Muljadi Budiman
2/1/2010 8:09 AM
Reply to Shimmy:

Please provide an email next time, so I can communicate possible answers directly, instead of using the comments system to reply to each other. You can also email me directly.

I've verified that Range actions is still not supported in .NET 4.

In VB.NET, the event declaration is just that; thus you have to use RaiseEvent to raise the event. However, behind the scenes, it actually creates a field for the event - the name of the field is <EventName>Event. In this case, the code will be as follows:

Dim handler As NotifyCollectionChangedEventHandler = CollectionChangedEvent

If (handler IsNot Nothing) Then
' Do stuff here
End If

I hope this help.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Shimmy
2/1/2010 10:22 AM
The VB version should be.

Protected Overrides Sub OnCollectionChanged(ByVal e As System.Collections.Specialized.NotifyCollectionChangedEventArgs)
If e.NewItems.Count > 1 Then
Dim handler As NotifyCollectionChangedEventHandler = GetType(ObservableCollection(Of T)).GetField("CollectionChanged", BindingFlags.Instance Or BindingFlags.NonPublic).GetValue(Me)
For Each invocation In handler.GetInvocationList
If TypeOf invocation.Target Is ICollectionView Then
DirectCast(invocation.Target, ICollectionView).Refresh()
Else
MyBase.OnCollectionChanged(e)
End If
Next
Else
MyBase.OnCollectionChanged(e)
End If
End Sub


Please do no share my email address.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Shimmy
2/1/2010 10:33 AM
Sorry I forgot to add Add check for NewItems null
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Logan
7/12/2010 11:29 AM
@Thomas--I'm pretty sure you can't do that. I thought it was a good idea and tried it out, but it turns out you can't modify the collection while Refresh is deferred. It is meant to allow setting up multiple CollectionView layers (filters, sorts, etc.), not adding items to the collection.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
investment in staffs
8/9/2010 5:46 AM
These are very good tips to know how to loose weight in less time. Thanks for your information.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
shipping vehicles
8/12/2010 11:11 PM
I am thankful to you for providing the information. I just want to know more on this. Thanks for sharing.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
poker rakeback
9/4/2010 2:35 AM
Agree with the other, very nice blog with useful stuff. Keep it coming.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
family portrait
9/25/2010 5:10 AM
Typically you ftp all the files from the web folder to the root of your web site on your web server. You should use the same approach when creating a package of files for deploying your custom feature.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
pc portable pas cher
1/17/2011 1:42 PM
Its well worth to read.I found it very informative as I have been researching a lot lately on practical matters thanks for sharing the info.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
2011 nike golf
1/18/2011 3:32 AM
I have been reading your blog for a while and thought I would completely pop in and drop a friendly note. . It is great stuff indeed. I also wanted to ask..is there a way to subscribe to your site via email?
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Diet Pill Reviews
2/1/2011 7:57 PM
Resources like the one you mentioned here will be very useful to me! I will post a link to this page on my blog. I am sure my visitors will find that very useful.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Kart Racing
2/22/2011 10:11 PM
I was just browsing for relevant blog posts for my project research and I happened to discover yours. Thanks for the useful information! :-)
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Richmond Carpet Repair
2/28/2011 4:17 AM
Nice information, many thanks to the author. It is incomprehensible to me now, but in general, the usefulness and significance is overwhelming. Thanks again and good luck..
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
orthotics
3/3/2011 11:58 PM
Wow nice information you have shared here. Actually Google made searching of information easy on any topic. Well keep it up and post more interesting blogs
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
chore cards
3/11/2011 10:00 PM
On weekends, I tend to go off tangent, and this weekend is no exception.I started to read some of the works of Levi-Strauss, the structural anthropologist.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
speed reading
3/11/2011 10:02 PM
It went well and I was thinking of generating the documentation using Visual Studio 2005 as I used to do in VS 2003. I could not find something like “ Build Comment Web Pages” under Tools and I realized that that option has been removed in 2005.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
DVD Duplication
3/11/2011 10:05 PM
I had applied your code in my work.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.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
mother eulogy
3/15/2011 11:50 PM
I cant believe how much of this I just wasn't aware of.Thank you for bringing more information to this topic for me.I'm truly grateful and really impressed.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
girls clothes
3/15/2011 11:52 PM
The closely at how well-maintained the public spaces and grounds of the building are. Burnt-out light bulbs in obvious areas may not be a good sign.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
how to last longer
3/16/2011 3:18 PM
Had a short training on VMWare on Tuesday, the software development department finally got the official permission to use VMWare Workstation.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
infrared outdoor heaters
3/17/2011 5:38 AM
Thanks a lot for presenting this beautiful blog with me. We are appreciating it very much and we are looking forward to another great blog. all the best for the author..
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Car Finance
3/20/2011 6:21 PM
Thank you for sharing us the codes. This would really help in the development of my thesis work.I learned a lot through this!
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Home Intercom
3/20/2011 10:54 PM
I just read through the entire article of yours and it was quite good. This is a great article thanks for sharing this informative information. I will visit your blog regularly for some latest post.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
WashingtonDC mover
3/21/2011 1:34 AM
This blog Is very informative , I am really pleased to post my comment on this blog . It helped me with ocean of knowledge so I really be live you will do much better in the future.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Raleigh Carpet Repair
3/26/2011 8:49 PM
Thank you for a great piece of info. Where else could anyone get that kind of information in such a perfect way of writing? I have a presentation next week and it is extremely helpful for me.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
liposuction beverly hills
3/27/2011 3:01 AM
Thanks for posting this info. I just want to let you know that I just check out your site and I find it very interesting and informative. I can’t wait to read lots of your posts.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
speed reading software
3/27/2011 3:05 AM
A lot of essay writers do the pre written essays about this good topic. So it is a very good opportunity to buy custom essay papers or written essays about this topic.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
chore game
3/27/2011 3:08 AM
Thanks for the great post. It reminds me that I have to bring more structure in to my blogging. Your blog is very interesting. Please let me know how to go for your rss blog.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
dc limo
3/27/2011 3:11 AM
Great little animated video. Community arts based projects are a great way of bringing people together. Will look you up on my next trip to the States.
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Allon Guralnek
8/17/2011 7:18 PM
Interestingly, you will only get that exception if your ObservableCollection implements the non-generic IList interface. If it doesn't implement that (e.g. it just implements the generic IList<T>), then you can raise collection change notification for multiple items and it will work wonderfully. Unfortunately, if you want your collection to be editable via data-binding you must implement the non-generic IList interface, otherwise you'll get the dreaded "InvalidOperationException: 'EditItem' is not allowed for this view." So you can have your collection editable or you can have it bulk-updateable, but you can't have both (at least from my attempts).
Gravatar
# re: ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items
Home Security
5/22/2012 7:43 AM
very interesting post, I will continue to read later posts

Post Comment

Title *
Name *
Email
Comment *