I need to capture old value, new value and property name in PropertyChanged event handler. The default implementation of INotifyPropertyChanged provides only name of the pro
As @Andy mentioned, you can implement INotifyPropetyChanging to get the old value, but storing is a big cumbersome, so I made a helper class NotifyPropertyChangingCache you can use as following:
class EntityBase : INotifyPropertyChanged, INotifyPropertyChanging
{ /* ... */ }
// initiating the entity
var entity = new EntityBase();
// initiating the cache:
var notifyPropertyChangingCache = new Ice1e0.ComponentModel.NotifyPropertyChangingCache();
entity.PropertyChanging += notifyPropertyChangingCache.OnPropertyChanging;
// your property changed event looks like this
entity.PropertyChanged += (s, e) =>
{
var oldValue = notifyPropertyChangingCache.GetLastPropertyValue(e.PropertyName);
// your code goes here ...
};
// when you are done with your entity, don't forget to remove the events (we don't want to create a memory leak ...)
entity.PropertyChanging -= notifyPropertyChangingCache.OnPropertyChanging;
//entity.PropertyChanged -= ... (I assume you use not a in-line method here as I did in this example)
You can't. Implement INotifyPropetyChanging as well. That will provide access to the old value. You can find example implementations for both interfaces in the documentation.
I am not understanding how to implement generic interface on my Entity class because T will change depending on data type of property
That's correct. The answer you're looking at isn't actually all that good an answer, because it contains code that doesn't compile or make sense.
The basic idea of raising the non-generic PropertyChanged
event by passing the generic args class that inherits the non-generic PropertyChangedEventArgs
class is by itself okay. It should work fine in your case.
But! You're not going to be able to implement the generic interface that answer proposes, because (as you already note) the interface doesn't work when the properties have different types. In fact, the answer you're looking at wouldn't even compile with that interface, because their event-raising method is itself generic, and raises the non-generic PropertyChanged
event (the method would be incompatible with the generic interface), and they don't bother to actually implement their generic interface (if they'd tried, they'd have noticed that the generic method doesn't work with the generic interface…the method's type parameter T
is different from the interface's type parameter T
).
It's unfortunate that highly up-voted answer was written that way. It has some useful ideas in it, but it also has completely unworkable ideas, and is going to just confuse exactly the people who are looking for an answer like that (i.e. the very people who most want to read and use the answer).
Just Implement your own PropertyChangedEventArgs.
Implemeting a new Interface not necessary.
This solutions works. Here is one of the benefits of polymorphism
public class PropertyChangedExtendedEventArgs : PropertyChangedEventArgs
{
public virtual object OldValue { get; private set; }
public virtual object NewValue { get; private set; }
public PropertyChangedExtendedEventArgs(string propertyName, object oldValue,
object newValue)
: base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
public class NotifyObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName, object oldvalue, object newvalue)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedExtendedEventArgs(propertyName, oldvalue, newvalue));
}
}
public class Person : NotifyObject
{
private int _name;
public int Name
{
get { return _name; }
set
{
var oldValue = _name;
_name = value;
NotifyPropertyChanged("Name", oldValue, value);
}
}
}
And your view model
Person person = new Person();
person.PropertyChanged += person_PropertyChanged;
void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var args = e as PropertyChangedExtendedEventArgs;
//do whatever you want
}