27

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
  • 25,418
  • 43
  • 131
  • 202

6 Answers6

60

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?

While there may be some "better" way which would involve using third party dependencies, some low level manipulation, etc. Simply looping over the collection is fine and works. I recommend doing that. In short—no, there is, effectively, no "better" way.


This is the old version of this answer, which is a misuse of LINQ (potentially iterating the collection twice just to save a line or two of code). I wanted to delete the answer entirely, but I can't, since it's the accepted answer.

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
  • 29,453
  • 4
  • 60
  • 67
  • 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
  • You can avoid the ToList(). I will execute 2 if you do it like this. The loop to convert to list and the one to add. Ilist inherits from Ienumerator so you can just `list.ForEach(obs.Add);` – Sergio Escudero Jun 09 '22 at 22:48
  • 1
    @SergioEscudero no, you can't – https://dotnetfiddle.net/7nbPiK – Adam Ralph Jun 11 '22 at 06:51
  • 1
    That said, this (12 year old) answer is indeed a misuse of LINQ, so I'm going to edit it. I can't delete it, because it's the accepted answer. – Adam Ralph Jun 11 '22 at 06:52
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,601
  • 1
  • 39
  • 36
RaYell
  • 69,610
  • 20
  • 126
  • 152
  • 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
  • 83,269
  • 19
  • 178
  • 237
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
  • 54,145
  • 21
  • 145
  • 203
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,549
  • 1
  • 20
  • 34
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.