Detect if ObservableCollection is changed

I have a DataGrid nested in a DockPanel. DockPanel serves as a data context:

DockPanel1.DataContext = GetData(); 

The GetData () method returns an ObservableCollection.

ObservableCollection can be changed in the DataGrid, as well as in several text boxes nested in the DockPanel. I also navigate the collection using a DataView.

I would like to determine if the collection has been changed and alert the user when he tries to close the application without saving data.

Is there a built-in mechanism that I could use (a kind of IsDirty flag in the collection or in the view)? If not, I think I will have to control all the controls and detect any changes manually.

Thank you Lesha

+1
source share
2 answers

To detect changes in the collection itself, you will need to attach CollectionChanged . If you also need to detect changes in the objects contained in the collection, you will need to bind PropertyChanged to each object (provided that the objects implement INotifyPropertyChanged).

The implementation will basically look like this:

 var collection = GetData(); collection.CollectionChanged += OnCollectionChanged; ... private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: AddPropertyChanged(e.NewItems); break; case NotifyCollectionChangedAction.Remove: RemovePropertyChanged(e.OldItems); break; case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Reset: RemovePropertyChanged(e.OldItems); AddPropertyChanged(e.NewItems); break; } ... } private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { ... } private void AddPropertyChanged(IEnumerable items) { if (items != null) { foreach (var obj in items.OfType<INotifyPropertyChanged>()) { obj.PropertyChanged += OnPropertyChanged; } } } private void RemovePropertyChanged(IEnumerable items) { if (items != null) { foreach (var obj in items.OfType<INotifyPropertyChanged>()) { obj.PropertyChanged -= OnPropertyChanged; } } } 
+3
source

To describe Clemens's answer in detail above, here is a simple way to use these events (in the collection and on elements) to implement the IsDirty flag, as you described:

 public class DirtyCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged { private bool isDirty = false; public bool IsDirty { get { return this.isDirty; } } public void Clean() { this.isDirty = false; } protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { // We aren't concerned with how the collection changed, just that it did. this.isDirty = true; // But we do need to add the handlers to detect property changes on each item. switch (e.Action) { case NotifyCollectionChangedAction.Add: this.AddPropertyChanged(e.NewItems); break; case NotifyCollectionChangedAction.Remove: this.RemovePropertyChanged(e.OldItems); break; case NotifyCollectionChangedAction.Replace: case NotifyCollectionChangedAction.Reset: this.RemovePropertyChanged(e.OldItems); this.AddPropertyChanged(e.NewItems); break; } base.OnCollectionChanged(e); } private void AddPropertyChanged(IEnumerable items) { if (items != null) { foreach (var obj in items.OfType<INotifyPropertyChanged>()) { obj.PropertyChanged += OnItemPropertyChanged; } } } private void RemovePropertyChanged(IEnumerable items) { if (items != null) { foreach (var obj in items.OfType<INotifyPropertyChanged>()) { obj.PropertyChanged -= OnItemPropertyChanged; } } } private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) { // A property of a contained item has changed. this.isDirty = true; } } 

The code should be clear enough.

You can, of course, delete "where T: INotifyPropertyChanged" so that objects that do not implement this interface should be stored in the collection, but then you will not be notified of changes to the properties on them, because without this interface, they cannot notify you of them.

And if you want to track not only that the collection is dirty, but also how, some additions to OnCollectionChanged and OnItemPropertyChanged to record information transmitted in the event could do it beautifully.

+1
source

Source: https://habr.com/ru/post/945106/


All Articles