How to detect if an item in my ObservableCollection has changed

24,230

Solution 1

  • Implement INotifyPropertyChanged in your Product class with notification for every property.
  • Implement INotifyPropertyChanged in your viewmodel.
  • Add property IsDirty to your ViewModel (with notification through INotifyPropertyChanged.
  • In your viewmodel, subscribe to CollectionChanged

    public YourViewModel()
    {
        ...
        YourCollection.CollectionChanged += YourCollection_CollectionChanged; 
        ...
    }
    
    private void YourCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args)
    {
        if (args.OldItems != null)
            foreach(var oldItem in args.OldItems)
                oldItem.PropertyChanged -= YourItem_PropertyChanged;
    
        if (args.NewItems != null)
            foreach(var newItem in args.NewItems)
                newItem.PropertyChanged += YourItem_PropertyChanged;
    }
    
    private void Youritem_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs args)
    {
        IsDirty = true;
    }
    
  • Now you can bind to IsDirty property of your viewmodel, for example, you can bind Button.IsEnabled property directly to it.

Solution 2

Just use the ObservableCollection. It has an event called CollectionChanged. If you register it, you can do what you want. Example:

ObservableCollection<string> strings = new ObservableCollection<string>();
strings.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(changed);
strings.Add("Hello");
strings[0] = "HelloHello";

And:

private void changed(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs args)
{
    //You get notified here two times.
}

Solution 3

The logic needs to go in your Model (Product class). A clean approach would be to expose IsDirty property (backed by field) in your model.

And your ViewModel would have a Command binding with CanSave checking the internal collection, and return true if Any of the item in collection IsDirty=true.

Share:
24,230
Charlie Kou
Author by

Charlie Kou

Updated on July 09, 2022

Comments

  • Charlie Kou
    Charlie Kou almost 2 years

    I have a datagrid which is bound to ObservableCollection<Product>. When the grid is updated this automatically updates the Product object in my collection.

    What I want to do now is to have some sort of even that is triggered when any object in the collection is updated -or- some sort of binding to the collection that will return true/false depedant on if any Product has been updated.

    The overall objective is to have a save button on my main window that is disabled if no changes have been made to my collection and enabled if changes have been made.

    I have read into INotifyPropertyChange but I dont see how I can use this to monitor changes on a whole collection.

    Additionally, if I implement this interface on my Product class I dont see how my UI can monitor every product in the collection - or can it?

  • Stealth Rabbi
    Stealth Rabbi about 11 years
    Despite the MSDN documentation, CollectionChanged doesn't get invoked when objects in the collection change. Only when the collectoin itself has objects added or deleted.
  • Oystein
    Oystein over 6 years
    This ought to be set as the answer.
  • Junior
    Junior about 6 years
    For this code to work, foreach(var oldItem in args.OldItems) should be changed to foreach(Product oldItem in args.OldItems) and foreach(var newItem in args.NewItems) to foreach(Product newItem in args.NewItems). Also this answer should be accepted