Replace Entire ObservableCollection with another ObservableCollection

Adam Szabo picture Adam Szabo · Aug 1, 2013 · Viewed 8.6k times · Source
public class Alpha
{
    public ObservableCollection<Beta> Items { get; set; }

    public Alpha()
    {
        Items = new ObservableCollection<Beta>();
    }

    public void DoSomething()
    {
        Items = GetNewItems();  // whenever I do this, Items gets a new referene, 
                                // so every WPF binding (e.g. datagrids) are broken
    }

    public ObservableCollection<Beta> GetNewItems()
    {
         var ret = new ObservableCollection<Beta>();
         // some logic for getting some items from somewhere, and populating ret
         return ret;
    }
}

How can I replace the whole content of Items with the return value of GetNewItems() without:

  1. Breaking the bindings.

  2. Having to loop through the items and copy them one by one to the other collection ?

Answer

Ty Morrow picture Ty Morrow · Aug 1, 2013

You have some options:

  1. Implement INotifyPropertyChanged so you can inform the UI that the value of Items has changed. This does not utilize the fact that INotifyCollectionChanged is implemented on ObservableCollection. It will work, but it defeats the purpose of using an ObservableCollection in the first place. This is not recommended but it works.
  2. Use the ObservableCollection's Add/Remove/Modify/Update methods to modify it in conjunction with the Dispatcher.
    • Note: without the Dispatcher, you will get a NotSupportedException because CollectionViews do not support changes to their SourceCollection from a thread different from the Dispatcher thread.
  3. Use the ObservableCollection's Add/Remove/Modify/Update methods to modify it in conjunction with BindingOperations.EnableCollectionSynchronization. Recommended
    • Note: This is only available in .NET 4.5.
    • This is an alternative to using the Dispatcher while avoiding the NotSupportedException.
    • Example

Numbers 2 and 3, with respect to your question, translate to clearing the existing items (Clear()) and then adding (Add()) the items returned by whatever method you want - see the example for #3. They key is that the clearing and all of the adding must be done with Dispatcher (2) or by calling BindingOperations.EnableCollectionSynchronization. Good luck!

Reference: Reed Copsey Answer - StackOverflow