0

I have implemented CollectionChanged for an ObservableCollection just like here: Implementing CollectionChanged

Is there a possibility in the OnCollectionChanged method to find out what the name of the changed property is?

EDIT: A history should be written if there is any change in the class. There are three cases I want to achieve:

  1. "Normal" property is changed (string, int, ...): this is already working
  2. Add and remove in collections: would be working if I know the name of the changed collection
  3. Property inside a collection is changed: same problem as 2) I don't know the name (and index) of the ch

    public class ParentClass : BaseModel
    {
        public ParentClass()
        {
            Children = new ObservableCollection<SomeModel>();
            Children.CollectionChanged += Oberservable_CollectionChanged;
        }
    
        private string id;
    
        public string Id
        {
            get
            {
                return id;
            }
            set
            {
                string oldId = id;
                id = value;
                OnPropertyChanged(oldArticleId,id);
            }
        }
    
        public ObservableCollection<SomeModel> Children { get; set; }
    
        protected virtual void OnPropertyChanged(object oldValue, object newValue, [CallerMemberName] string propertyName = null)
        {
            //1) Entry is added to history (this part is working)
        }
    
    
        protected void Oberservable_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (INotifyPropertyChanged added in e.NewItems)
                {
                    added.PropertyChanged += OnPropertyChangedHandler;
                    OnCollectionChanged(CollectionChangedModel.Action.Added, added);
                }
            }
    
            if (e.OldItems != null)
            {
                foreach (INotifyPropertyChanged removed in e.OldItems)
                {
                    removed.PropertyChanged -= OnPropertyChangedHandler;
                    OnCollectionChanged(CollectionChangedModel.Action.Removed, removed);
                }
            }
        }
    
        protected virtual void OnCollectionChanged(CollectionChangedModel.Action action, object value)
        {
            //2) TODO: History should be written, but I don't have the property name
        }
    
        public void OnPropertyChangedHandler(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
        {
            //3) TODO: History about changed property in child-class (not working because of missing property name and index)
        }
    }
    
Pinzi
  • 263
  • 3
  • 15
  • 2
    Correct me if i'm wrong, but isn't `collectionChanged` intended to notify whenever the *collection* changes, rather than an *item in the collection*? – Timothy Groote Jul 03 '17 at 09:04
  • Did you read https://stackoverflow.com/questions/8577207/better-propertychanged-and-propertychanging-event-handling – BugFinder Jul 03 '17 at 09:04
  • 1
    That's *not* a CollectionChanged implementation, that's an event listener. You *do* know who raised the event - you get the `sender` as a parameter – Panagiotis Kanavos Jul 03 '17 at 09:05
  • @TimothyGroote: yes, but the collection is a property in another class and I need to know the name of this property (name of the collection) – Pinzi Jul 03 '17 at 09:07
  • 3
    @Pinzi then *that* class has to implement INotifyPropertyChanged and you should listen to that interface and handle its events. If you use data bidning, you don't have to do anything really. When you set up data binding, the controls subscribe to the notifications automatically – Panagiotis Kanavos Jul 03 '17 at 09:07
  • @PanagiotisKanavos: But how can I implement INotifyPropertyChanged for a list? – Pinzi Jul 03 '17 at 09:09
  • @Pinzi what do you even mean "implement"? You already asked about "implementation" but linked to a *listener* question. Implementing `INotifyPropertyChanged` or `INotifyCollectionChanged` means you write the code that *raises* the corresponding events. It doesn't matter whether you raise `INotifyPropertyChanged` for a list or integer, the code is the same. – Panagiotis Kanavos Jul 03 '17 at 09:12
  • @PanagiotisKanavos: But it is not firing when I add an item to the list or remove an item. And want to have a history of all the changes in a class. – Pinzi Jul 03 '17 at 09:15
  • Please share the code you have written, like an [MCVE](https://stackoverflow.com/help/mcve) so it is easer to give you suggestions about the implementation – Icepickle Jul 03 '17 at 09:18

1 Answers1

1

This is correct:

Children = new ObservableCollection<SomeModel>();
Children.CollectionChanged += Oberservable_CollectionChanged;

Though you have to ensure nobody will change collection, e.g. like this:

public ObservableCollection<SomeModel> Children { get; }

or rather making it a full property and subscribing/unsubscribing in the setter.

And now regarding Oberservable_CollectionChanged handler:

  1. Add and remove in collections: would be working if I know the name of the changed collection

Add sender to your event. Wrap arguments into ...EventArgs class (make it immutable), see msdn.

public event EventHandler<MyCollectionChangedEventArgs> CollectionChanged;
protected virtual void OnCollectionChanged(object sender, MyCollectionChangedEventArgs e)
{
    //2) TODO: History should be written, but I don't have the property name

    // sender is name
    // e.Action and e.Value are parameters
}
  1. Property inside a collection is changed: same problem as 2) I don't know the name (and index) of the ch

Wrap event handlers into instance containing event handler and value you need (I am leaving that task for you). If unsubscribing is not required, this can be easily achieved by using lamdba closures:

foreach (var added in e.NewItems.OfType<INotifyPropertyChanged>)
{
    added.PropertyChanged += (s, e) => 
    {
        // you have `sender` here in addition to `s`, clever?
    };
}
Sinatr
  • 18,856
  • 9
  • 75
  • 248