ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

Joseph jun. Melettukunnel picture Joseph jun. Melettukunnel · Sep 15, 2009 · Viewed 183.8k times · Source

Does anyone know why this code doesn't work:

public class CollectionViewModel : ViewModelBase {  
    public ObservableCollection<EntityViewModel> ContentList
    {
        get { return _contentList; }
        set 
        { 
            _contentList = value; 
            RaisePropertyChanged("ContentList"); 
            //I want to be notified here when something changes..?
            //debugger doesn't stop here when IsRowChecked is toggled
        }
     }
}

public class EntityViewModel : ViewModelBase
{

    private bool _isRowChecked;

    public bool IsRowChecked
    {
        get { return _isRowChecked; }
        set { _isRowChecked = value; RaisePropertyChanged("IsRowChecked"); }
    }
}

ViewModelBase containts everything for RaisePropertyChanged etc. and it's working for everything else except this problem..

Answer

simon picture simon · Mar 10, 2011

Here is a drop-in class that sub-classes ObservableCollection and actually raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.

The benefit here is that you can data bind to this class and all of your bindings will update with changes to your item properties.

public sealed class TrulyObservableCollection<T> : ObservableCollection<T>
    where T : INotifyPropertyChanged
{
    public TrulyObservableCollection()
    {
        CollectionChanged += FullObservableCollectionCollectionChanged;
    }

    public TrulyObservableCollection(IEnumerable<T> pItems) : this()
    {
        foreach (var item in pItems)
        {
            this.Add(item);
        }
    }

    private void FullObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (Object item in e.NewItems)
            {
                ((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
            }
        }
        if (e.OldItems != null)
        {
            foreach (Object item in e.OldItems)
            {
                ((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
            }
        }
    }

    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {            
        NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
        OnCollectionChanged(args);
    }
}