26

I have an ObservableCollection, and I'd like to set the content of an IList to this one. Now I could just create a new instance of the collection..:

public ObservableCollection<Bar> obs = new ObservableCollection<Bar>(); 
public void Foo(IList<Bar> list)
{
    obs = new ObservableCollection<Bar>(list); 
}

But how can I actually take the content of the IList and add it to my existing ObservableCollection? Do I have to loop over all elements, or is there a better way?

public void Foo(IList<Bar> list)
{
   foreach (var elm in list)
       obs.Add(elm); 
}
stiank81
  • 24,988
  • 41
  • 129
  • 201

6 Answers6

57

You could do

public void Foo(IList<Bar> list)
{
    list.ToList().ForEach(obs.Add);
}

or as an extension method,

    public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items)
    {
        items.ToList().ForEach(collection.Add);
    }    
Adam Ralph
  • 28,433
  • 4
  • 58
  • 64
  • Thx! Went with the ToList.ForEach approach for now. Will consider extension method if I need this more than one place.. – stiank81 Feb 02 '10 at 13:35
  • The `Enumerable.ToList` extension method needlessly allocates a new `List`. I'd probably recommend RaYell's answer. – Richard Szalay Feb 02 '10 at 13:58
  • 3
    @Richard - that is true although under the hood this does new List(list) - which internally calls ((ICollection)list).CopyTo(T[]) which in most implementations of IList (e.g. List) calls a native (external) array copy function. this should be quite efficient and only involve (at most) an atomic copy of the necessary references rather than iteration of members. – Adam Ralph Feb 02 '10 at 18:15
  • In Prism 4, it is CollectionExtensions.AddRange (http://msdn.microsoft.com/en-us/library/gg405741(v=pandp.40).aspx). – Neo May 01 '12 at 09:37
11

You could write your own extension method if you are using C#3+ to help you with that. This code has had some basic testing to ensure that it works:

public static void AddRange<T>(this ObservableCollection<T> coll, IEnumerable<T> items)
{
    foreach (var item in items)
    {
        coll.Add(item);
    }
}
Brian Hinchey
  • 3,501
  • 1
  • 41
  • 36
RaYell
  • 68,096
  • 20
  • 124
  • 150
  • 1
    Microsoft's [Prism](http://compositewpf.codeplex.com/) project for WPF includes a similar extension method (although, their version returns the collection, rather than `void`, to support method chaining). Just reference Microsoft.Practices.Composite.dll and add `using Microsoft.Practices.Composite;`. – totorocat Oct 15 '10 at 02:27
1

Looping is the only way, since there is no AddRange equivalent for ObservableCollection.

Richard Szalay
  • 81,010
  • 19
  • 172
  • 232
0

Here is an descendant to ObservableCollection<T> to add a message efficient AddRange, plus unit tests:

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

Community
  • 1
  • 1
weston
  • 52,585
  • 20
  • 135
  • 197
0

There is a library that solves this problem. It contains an ObservableList that can wrap a List. It can be used in the following way:

List<Bar> currentList = getMyList();
var obvList = new ObservableList<Bar>(currentList);

https://github.com/gsonnenf/Gstc.Collections.ObservableLists

Greg
  • 1,434
  • 1
  • 19
  • 32
0

If you do want to instantiate an observable collection and want to add a new range into Observable collection you can follow the following method I have tried:

var list = new List<Utilities.T>();
            list.AddRange(order.ItemTransactions.ToShortTrans());
            list.AddRange(order.DealTransactions.ToShortTrans());
            ShortTransactions = new ObservableCollection<T>(list);

in this way you can add the range into ObservableCollection without looping.