24

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?

Richard Anthony Hein
  • 10,550
  • 3
  • 42
  • 62
Remotec
  • 10,304
  • 25
  • 105
  • 147
  • 1
    See here: http://stackoverflow.com/questions/1427471/observablecollection-not-noticing-when-item-in-it-changes-even-with-inotifyprop – SwDevMan81 Jan 24 '12 at 11:44
  • 1
    I'm using this: http://stackoverflow.com/questions/8490533/notify-observablecollection-when-item-changes – Noich Jan 17 '13 at 13:46

4 Answers4

22
  • 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.

chopikadze
  • 4,219
  • 26
  • 30
  • This ought to be set as the answer. – Oystein Sep 20 '17 at 20:27
  • 1
    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 – Junior Apr 23 '18 at 22:58
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.
}
Skalli
  • 2,707
  • 3
  • 27
  • 39
  • 29
    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. – Stealth Rabbi Mar 04 '13 at 12:51
1

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.

Naser Asadi
  • 1,153
  • 18
  • 35
Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
0

I think subscribing to the PropertyChanged event for each of the objects in your collection and firing this event, for example, in the setter of your objects can work.

However, I think you don't need to do all this to figure out if a cell is changed in your grid. I think you can do something like what they do here instead:

http://social.msdn.microsoft.com/Forums/en/wpf/thread/81131225-90fb-40f9-a311-066952c7bc43

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Orkun
  • 6,998
  • 8
  • 56
  • 103