13

What are the potential problems caused by an ObservableCollection supporting operations like AddRange or RemoveRange? There must be a reason why Microsoft didn't provide them, now that ObservableCollection is so frequently used with WPF.

You could implement your own collection that supports bulk operations and implements INotifyCollectionChanged. What happens if I bind such a control to an ItemsControl?

Does anyone know of ItemsControls that don't support bulk changes?

DanT
  • 3,960
  • 5
  • 28
  • 33
  • 7
    There is a BulkObservableCollection class in Microsoft.VisualStudio.Language.Intellisense.BulkObservableCollection http://msdn.microsoft.com/en-us/library/dd867973.aspx – tofutim Nov 21 '12 at 14:37

4 Answers4

4

There are numerous extensions to ObservableCollection that can be found on the internet that add the concept of add / remove range, or allow you to defer updates and fire them manually. For example see this Stack Overflow question:

ObservableCollection Doesn't support AddRange method, so I get notified for each item added, besides what about INotifyCollectionChanging?

You can also implement a bulk add that fires a reset event, which will cause the UI to re-render all of the items in the collection:

http://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/

These allow you to more efficiently manage the UI updates. How an ItemsControl handles a collection changed event which details a list of changed items is up to the WPF framework itself. I am assuming it handles this intelligently!

My advice to you is, if performance is critical to you and you have collections with numerous items being updated and are experiencing performance problem, then subclass ObservableCollection to manage collection changed notification in a manner that best fits your application's needs.

Community
  • 1
  • 1
ColinE
  • 68,894
  • 15
  • 164
  • 232
  • 1
    A quick glance at the implementation of the linked question shows an inefficient implementation. Basically, the `CollectionChanged` event is raised for every item added, then again to reset the collection! – Kent Boogaart Mar 05 '12 at 17:12
  • 1
    @KentBoogaart hi Kent, do you mean the SO answer? looks fine to me. The AddRange method iterates over the items added then fires a single CollectionChanged event, with a change type of 'add' supplying the list of added items. The formatting of the code is not so good though ;-) – ColinE Mar 05 '12 at 17:15
  • 1
    since the RangeObservableCollection extends ObservableCollection, calling Add on every item results in the CollectionChangedEvent being raised for every item added. Then all that effort goes to waste by resetting the collection after all the items are added. – Kent Boogaart Mar 05 '12 at 18:19
  • 3
    Except that it doesn't, because the code linked also overrides OnCollectionChanged to suppress the CollectionChangedEvent if a flag is set; the AddRange method sets this flag, loops through and calls Add for each item, and then unsets the flag. – Chris May 01 '13 at 08:28
4

I don't think it's that there are any potential downsides or problems, it's just that it isn't there. In fact, you will find that most types in 'System.Collections.Generic' don't supply 'AddRange' functionality either.

Meanwhile, lots of people have created their own versions of 'ObservableCollection' to provide the functionality that you want. INotifyCollectionChanged contains enough information for its handlers to make note of when a range of items have been affected probably for this reason.

Last but not least, if you bind a collection that has these 'Range' type operations you will find that they will work with your UI as you expect

A.R.
  • 15,405
  • 19
  • 77
  • 123
2

NotifyCollectionChangedEventArgs includes index information. Removing items causes indexes to reshuffle, as does inserting items. Hence, whilst not entirely impossible, it would be rather difficult and probably inefficient to provide the ability to work with ranges.

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
  • The only index information is "the index at which the change occurred". This information is easily provided with add and remove range operations. – A.R. Mar 05 '12 at 18:34
  • @A.R.: nope, what if I remove the first and last items of the collection? There's only one index in the event args, but two indexes are necessary. – Kent Boogaart Mar 05 '12 at 18:39
  • There are two indexes. There is 'NewStartingIndex' and 'OldStartingIndex'. The latter's description reads "Gets the index at which a Move, Remove, or Replace action occurred.", Also, unless you are removing ALL of the items in the collection, the scenario you are describing isn't possible since elements in a range are contiguous. – A.R. Mar 05 '12 at 18:49
  • 1
    My bad - I misread the OP. I thought the question was about why there is no `RemoveAll`, as there is with `List`. You're right: `AddRange`/`RemoveRange` would be very easy to provide. – Kent Boogaart Mar 05 '12 at 20:38
1

There must be a reason why Microsoft didn't provide them

They do not provide every possible piece of functionality, it's (also) a cost vs. demand thing.

You could implement your own collection that supports bulk operations and implements INotifyCollectionChanged.

Yes. And when you do, you'll find that the collection will have to make choices about how/when to propagate those changes. I never tried but I imagine there are some trade-offs that the View or ViewModel can make better decisions about than a reusable collection.

H H
  • 263,252
  • 30
  • 330
  • 514