Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CollectionChanged and IList of Items - why the difficulties

I am looking into the topic why a ObservableCollection/ListCollectionView/CollectionView raises a NotSuportedException when calling the CollectionChanged with the parameter of IList.

//Throws an exception
private void collectionChanged_Removed(IList items)
{
    if (CollectionChanged != null)
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, items));
}

I have found several Webpages, talking about this topic and they suggest either using the Reset ability to force a complete redraw of the UI, or just simply call for each item the CollectionChanged or some more creative way: http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/listcollectionviewcollectionview-doesnt-support-notifycollectionchanged-with-multiple-items.aspx

I just cant find the WHY? For me it makes no sense why this would be the case.

Is there any chance that this lacking feature, which we all face at some point in our Development Cycle, since the Add method just has to much of an overhead when you want to Add multiple items fast, will be implemented any time (.Net 5, C# 6...).

Edit:

In my specific case, I have written my own class :

public class ObservableList<T> : IList<T>, IList, IEnumerable<T>,
    INotifyCollectionChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;
    //other stuff...
}

And still throws the said NotSupportedException.

like image 697
Rand Random Avatar asked Feb 04 '14 16:02

Rand Random


2 Answers

Inspired by VirtualBlackFox's answer I took a look under the hood of the CollectionView classes in ILSpy. It appears that the primary reason why the lack of support for Range operations is because internally the CollectionView uses a change log to centrally manage pending changes of all kinds and dispatch messages on a per/item basis.

By its very purpose, the CollectionView could store 1000s of records used simultaneously with multiple UI controls representing its underlying data. So, adding or deleting records must be done on an atomic basis to maintain the integrity of the UI controls that access the view information. You can't synchronize incremental changes with multiple UI subscribers using bulk change events without passing the grouping, sorting, and filtering functionality of the CollectionView onto the UI controls that use it.

The CollectionView also derives from System.Windows.Threading.Dispatcher so the issue may be co-related to how it manages work items on it's thread. The call path includes a protected ProcessCollectionChanged method that specifically processes individual changes on the UI thread. So, updating ranges may interfere with the whole threading model it uses to interact with UI elements that use it.

I totally agree that having consumers of the CollectionView pass in an IList to NotifyCollectionChangedEventArgs is silly. It specifically rejects anything with a length != 1 and hard-codes for args.NewItems[0] internally.

like image 196
drankin2112 Avatar answered Nov 10 '22 08:11

drankin2112


As @nmclean said in the comments the problem isn't in the collection emitting CollectionChanged but on the receiving end.

If you look at the code of ListCollectionView (Using DotPeek for example or on new versions of visual studio you can access the reference source code) you will notice that each time the attached collection change it call a method ValidateCollectionChangedEventArgs that throw when there is more than one element changed

private void ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
{
  switch (e.Action)
  {
    case NotifyCollectionChangedAction.Add:
      if (e.NewItems.Count == 1)
        break;
      else
        throw new NotSupportedException(System.Windows.SR.Get("RangeActionsNotSupported"));
...

The rest of the class and it's CollectionView base class are already big beasts (2710 and 2027 lines in the source published on the reference source code) so Microsoft might have wanted to avoid supporting a complex case that the collection that they recommend don't create anyway.

(The method handling collection change is already 141 lines in the reference source code and adding multi element support will make it grow even more or need a careful split and potentially break other things...)

I didn't find any suggestions linked to adding support for range events in Microsoft Connect but you should submit your own if it is important for you.

like image 2
Julien Roncaglia Avatar answered Nov 10 '22 09:11

Julien Roncaglia