Для бизнес-приложений, имеющих общий базовый класс, я делаю это согласно
Реализация INotifyPropertyChanged - существует ли лучший способ?
с некоторыми изменениями для проверки "пузырящихся" свойств.
Базовый класс
public bool HasAlteredState { get; protected set; }
public event PropertyChangedEventHandler PropertyChanged;
private void propertyObject_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.OnPropertyChanged(e.PropertyName);
}
protected virtual void RegisterSubPropertyForChangeTracking(INotifyPropertyChanged propertyObject)
{
propertyObject.PropertyChanged += new PropertyChangedEventHandler(propertyObject_PropertyChanged);
}
protected virtual void DeregisterSubPropertyForChangeTracking(INotifyPropertyChanged propertyObject)
{
propertyObject.PropertyChanged -= propertyObject_PropertyChanged;
}
protected virtual void OnPropertyChanged(string propertyName)
{
this.HasAlteredState = true;
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
if (field is INotifyPropertyChanged)
{
if (field != null) { this.DeregisterSubPropertyForChangeTracking((INotifyPropertyChanged)field); }
}
if (value is INotifyPropertyChanged)
{
if (value != null) { this.RegisterSubPropertyForChangeTracking((INotifyPropertyChanged)value); }
}
field = value;
OnPropertyChanged(selectorExpression);
return true;
}
Подклассы
private IndividualName _name;
public IndividualName PersonName
{
get { return _name; }
set { SetField(ref _name, value, () => PersonName); }
}
Обеспечивает
- Простое уведомление об изменении свойства
- Сложное уведомление об изменении свойства
- Событие «всплывающее» из INotifyPropertyChanged реализации глубже в графе объектов
- Время компиляции, проверяющее, что «имя» вашей собственности действительно относится к вашей собственности. т.е. избегать неприятных ошибок, связанных с неправильным написанием имени свойства при использовании только строки.
Производительность
С этим подходом связано снижение производительности ... примерно на 20% медленнее, чем при использовании строки. Тем не менее, хотя метрики и трассировка говорят о том, что он медленнее, я на самом деле не могу понять разницу, поэтому хит того стоит: обслуживание приложений для тех видов приложений, которые я участвую в разработке.
Альтернативные реализации
- Если базовый класс не является опцией, вы можете пойти по маршруту метода Extension.
Для лучшей производительности вы можете использовать два разных метода SetField; первый SetNotifyField будет иметь дело со свойствами, которые сами реализуют INotifyPropertyChanged (как указано выше), а второй SetField будет иметь дело с простыми свойствами. то есть вырезать
if (поле INotifyPropertyChanged) ...