Search code examples
c#asp.netpropertiespropertychanged

Capture property change using its setter


I want to be notified when a property changes so that I can log the oldvalue and new value of the property in database.

So I decided to go with the approach of property setter and have a generic method that handles all properties.

I created below class:

public class PropertyChangedExtendedEventArgs<T> : PropertyChangedEventArgs
{
    public virtual T OldValue { get; private set; }
    public virtual T NewValue { get; private set; }

    public PropertyChangedExtendedEventArgs(string propertyName,
                                            T oldValue, T newValue)
        : base(propertyName)
    {
        OldValue = oldValue;
        NewValue = newValue;

   //write to database the values!!!
    }
}

and on my property I call it as such:

private string _surname;
public string Surname
{
    get { return _surname; }
    set 
    {
        string temp = Surname;
        _surname = value;
        Helper.PropertyChangedExtendedEventArgs("Surname", temp, value);
    }
}

but it is first time working with generics so got few concerns :

  • how do I call this on my property?
  • is this a good approach?
  • would I be able to call a function in public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue) and save to database?

Solution

  • You seem to have got a bit of confused in property change usage.
    Typically, components that wish to be observable about their property changes INotifyPropertyChanged interface. So as such correct implementation would be something like

    private string _surname;
    public string Surname
    {
        get { return _surname; }
        set 
        {
            if (_surname != value) // IMP: you want to inform only if value changes
            {
               string temp = Surname;
               _surname = value;
    
               // raise property change event, 
               NotifyPropertyChanged(temp, _surname);
            }
        }
    }
    

    Typically, base implementation could provide helper implementation to raise the event - for example,

    public abstract Component : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void NotifyPropertyChanged<T>(T oldVal, T newVal, [CallerMemberName] String propertyName = "")
        {
           var e = PropertyChanged;
           if (e != null)
           {
              e(this, new PropertyChangedExtendedEventArgs(propertyName, oldVal, newVal));
           }
        }
    }
    

    Now, its consumer's responsibility on how to react to property changes. This separates observable components from unrelated concern of what to do when some property changes. Typically, one will have some the common implementation that would say - save the current object state in stacked manner as to provide undo-redo functionality.

    So in your case, you wish to log them to database (?), there should be code that would listen to this property change events and does the logging. There will be some controller/binding code that would iterate through all objects implementing this interface and hook up the event. Typically, the root level container does such house keeping - for example, in a designer surface, its the root element (or code that is handling root element) would hook up event whenever a new component is created and added to the design surface.