Search code examples
c#entity-frameworkinotifycollectionchangedentitycollection

EntityFramework EntityCollection Observing CollectionChanged


I'm using EntityFramework database first in an application. I would like somehow to be notified of changes to an EntityCollection in my ViewModel. It doesn't directly support INotifyCollectionChanged (why?) and I haven't been successful in finding another solution.

Here's my latest attempt, which doesn't work because the ListChanged event doesn't appear to get raised:

public class EntityCollectionObserver<T> : ObservableCollection<T>, INotifyCollectionChanged where T : class
{
    public event NotifyCollectionChangedEventHandler CollectionChanged;

    public EntityCollectionObserver(EntityCollection<T> entityCollection)
        : base(entityCollection)
    {
        IBindingList l = ((IBindingList)((IListSource)entityCollection).GetList());
        l.ListChanged += new ListChangedEventHandler(OnInnerListChanged);
    }

    private void OnInnerListChanged(object sender, ListChangedEventArgs e)
    {
        if (CollectionChanged != null) 
            CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

Does anyone have any ideas how I might observe changes to an EntityCollection?

Dan


Solution

  • Whilst it worked in the simple use case noted by @Aron, I couldn't get it to work properly in my actual application.

    As it turns out, and for reasons I'm not sure - the inner IBindingList of an EntityCollection somehow, somewhere, can get changed. The reason my observers weren't being called is because they were looking for changes on an old IBindingList that wasn't even being used by the EntityCollection any more.

    Here is the hack that got it working for me:

    public class EntityCollectionObserver<T> : ObservableCollection<T> where T : class
    {
        private static List<Tuple<IBindingList, EntityCollection<T>, EntityCollectionObserver<T>>> InnerLists 
            = new List<Tuple<IBindingList, EntityCollection<T>, EntityCollectionObserver<T>>>();
    
        public EntityCollectionObserver(EntityCollection<T> entityCollection)
            : base(entityCollection)
        {
            IBindingList l = ((IBindingList)((IListSource)entityCollection).GetList());
            l.ListChanged += new ListChangedEventHandler(OnInnerListChanged);
    
    
            foreach (var x in InnerLists.Where(x => x.Item2 == entityCollection && x.Item1 != l))
            {
                x.Item3.ObserveThisListAswell(x.Item1);
            }
            InnerLists.Add(new Tuple<IBindingList, EntityCollection<T>, EntityCollectionObserver<T>>(l, entityCollection, this));
        }
    
        private void ObserveThisListAswell(IBindingList l)
        {
            l.ListChanged += new ListChangedEventHandler(OnInnerListChanged);
        }
    
        private void OnInnerListChanged(object sender, ListChangedEventArgs e)
        {
            base.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
        }
    }