Implement AddRange on ObservableCollection with proper support for DataBinding

src091 picture src091 · Jan 29, 2013 · Viewed 8.9k times · Source

I would like my own descendant of ObservableCollection to support AddRange method. Here is what I currently have:

public class ObservableCollectionPlus<T> : ObservableCollection<T>
{
    public void InsertRange(IEnumerable<T> items)
    {
        this.CheckReentrancy();
        foreach (var item in items) Items.Add(item);

        var type = NotifyCollectionChangedAction.Reset;
        var colChanged = new NotifyCollectionChangedEventArgs(type);
        var countChanged = new PropertyChangedEventArgs("Count");

        OnPropertyChanged(countChanged);
        OnCollectionChanged(colChanged);
    }
}

I don't have much knowledge of what's exactly going on here and why are these events get raised. This is a solutiom that I've assembled after doing some research on google and stackoverflow.

Now, if I bind an instance of my class to say LongListSelector then, after dynamically adding items via InsertRange to ObservableCollectionPlus, a binded LongListSelector's scroll position is sent to it's top.

If I add items in this standard way: foreach (var item in items) collection.Add(item); then LongListSelector's position does not get shifted. But of course this way I get DataBinding notifications overhead in which is undesired.

Apparently, something is done wrong in my current solution. How can I implement InsertRange that will behave exactly like foreach (var item in items) collection.Add(item); but will only fire DataBinding notification once and will not do strange things to binded object's scroll position?

Answer

sa_ddam213 picture sa_ddam213 · Jan 29, 2013

It could be because your sending the NotifyCollectionChangedAction.Reset notification, maybe just the NotifyCollectionChangedAction.Add will work, Maybe :)

public class ObservableRangeCollection<T> : ObservableCollection<T>
{
    public void AddRange(IEnumerable<T> collection)
    {
        foreach (var i in collection)
        {
            Items.Add(i);
        }
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, collection.ToList()));
    }
}