Как показывают ответы, мне пришлось реализовать собственное решение.Для удобства других я представил его здесь:
Расширенное событие PropertyChanged
Это событие было специально разработано для обратной совместимости со старыми событиями propertyChanged.Он может быть использован взаимозаменяемо с простым PropertyChangedEventArgs вызывающими.Конечно, в таких случаях ответственность за проверку того, может ли переданный PropertyChangedEventArgs быть передан в PropertyChangedExtendedEventArgs, если они хотят его использовать, лежит на обработчике события.Нет необходимости в даункинге, если все, что их интересует, это свойство PropertyName.
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;
}
}
Расширенный интерфейс PropertyChanged
If, программист хотел создать событиечто заставляет уведомляющих свойств включать старое значение и новое значение, им нужно только реализовать следующий интерфейс:
// Summary: Notifies clients that a property value is changing, but includes extended event infomation
/* The following NotifyPropertyChanged Interface is employed when you wish to enforce the inclusion of old and
* new values. (Users must provide PropertyChangedExtendedEventArgs, PropertyChangedEventArgs are disallowed.) */
public interface INotifyPropertyChangedExtended<T>
{
event PropertyChangedExtendedEventHandler<T> PropertyChanged;
}
public delegate void PropertyChangedExtendedEventHandler<T>(object sender, PropertyChangedExtendedEventArgs<T> e);
Пример 1
Теперь пользователь может указать более продвинутый метод NotifyPropertyChanged
, который позволяет установщикам свойств передавать свое старое значение:
public String testString
{
get { return testString; }
set
{
String temp = testString;
testValue2 = value;
NotifyPropertyChanged("TestString", temp, value);
}
}
Где ваш новый метод NotifyPropertyChanged
выглядит следующим образом:
protected void NotifyPropertyChanged<T>(string propertyName, T oldvalue, T newvalue)
{
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(propertyName, oldvalue, newvalue));
}
И OnPropertyChanged
- то же, что и всегда:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
Пример 2
Или если вы предпочитаете использовать лямбда-выражения и делатьполностью избавившись от жестко запрограммированных строк с именами свойств, вы можете использовать следующее:
public String TestString
{
get { return testString; }
private set { SetNotifyingProperty(() => TestString, ref testString, value); }
}
, что поддерживается следующей магией:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
Производительность
Если производительность является проблемой, см. Этот вопрос: Imдополняет NotifyPropertyChanged без волшебных строк .
Таким образом, накладные расходы минимальны.Добавление старого значения и переключение на расширенное событие приводит к замедлению примерно на 15%, при этом допускается порядка одного миллиона уведомлений о свойствах в секунду, а переключение на лямбда-выражения - это пятикратное замедление, позволяющее получать около ста тысяч уведомлений о свойствах в секунду.второй.Эти цифры далеки от того, чтобы создавать узкое место в любом приложении, управляемом пользовательским интерфейсом.