Search code examples
c#performancecollectionsinsertobservablecollection

Adding a range of values to an ObservableCollection efficiently


I have an ObservableCollection of items that is bound to a list control in my view.

I have a situation where I need to add a chunk of values to the start of the collection. Collection<T>.Insert documentation specifies each insert as an O(n) operation, and each insert also generates a CollectionChanged notification.

Therefore I would ideally like to insert the whole range of items in one move, meaning only one shuffle of the underlying list, and hopefully one CollectionChanged notification (presumably a "reset").

Collection<T> does not expose any method for doing this. List<T> has InsertRange(), but IList<T>, that Collection<T> exposes via its Items property does not.

Is there any way at all to do this?


Solution

  • The ObservableCollection exposes an protected Items property which is the underlying collection without the notification semantics. This means you can build a collection that does what you want by inheriting ObservableCollection:

    class RangeEnabledObservableCollection<T> : ObservableCollection<T>
    {
        public void InsertRange(IEnumerable<T> items) 
        {
            this.CheckReentrancy();
            foreach(var item in items)
                this.Items.Add(item);
            this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }
    

    Usage:

    void Main()
    {
        var collection = new RangeEnabledObservableCollection<int>();
        collection.CollectionChanged += (s,e) => Console.WriteLine("Collection changed");
        collection.InsertRange(Enumerable.Range(0,100));
        Console.WriteLine("Collection contains {0} items.", collection.Count);  
    }