Я новичок в .NET и WPF, поэтому надеюсь, что правильно задам вопрос. Я использую INotifyPropertyChanged, реализованный с помощью PostSharp 1.5:
[Serializable, DebuggerNonUserCode, AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = false),
MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false, Inheritance = MulticastInheritance.None, AllowExternalAssemblies = true)]
public sealed class NotifyPropertyChangedAttribute : CompoundAspect
{
public int AspectPriority { get; set; }
public override void ProvideAspects(object element, LaosReflectionAspectCollection collection)
{
Type targetType = (Type)element;
collection.AddAspect(targetType, new PropertyChangedAspect { AspectPriority = AspectPriority });
foreach (var info in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => pi.GetSetMethod() != null))
{
collection.AddAspect(info.GetSetMethod(), new NotifyPropertyChangedAspect(info.Name) { AspectPriority = AspectPriority });
}
}
}
[Serializable]
internal sealed class PropertyChangedAspect : CompositionAspect
{
public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs)
{
return new PropertyChangedImpl(eventArgs.Instance);
}
public override Type GetPublicInterface(Type containerType)
{
return typeof(INotifyPropertyChanged);
}
public override CompositionAspectOptions GetOptions()
{
return CompositionAspectOptions.GenerateImplementationAccessor;
}
}
[Serializable]
internal sealed class NotifyPropertyChangedAspect : OnMethodBoundaryAspect
{
private readonly string _propertyName;
public NotifyPropertyChangedAspect(string propertyName)
{
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
_propertyName = propertyName;
}
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
var targetType = eventArgs.Instance.GetType();
var setSetMethod = targetType.GetProperty(_propertyName);
if (setSetMethod == null) throw new AccessViolationException();
var oldValue = setSetMethod.GetValue(eventArgs.Instance, null);
var newValue = eventArgs.GetReadOnlyArgumentArray()[0];
if (oldValue == newValue) eventArgs.FlowBehavior = FlowBehavior.Return;
}
public override void OnSuccess(MethodExecutionEventArgs eventArgs)
{
var instance = eventArgs.Instance as IComposed<INotifyPropertyChanged>;
var imp = instance.GetImplementation(eventArgs.InstanceCredentials) as PropertyChangedImpl;
imp.OnPropertyChanged(_propertyName);
}
}
[Serializable]
internal sealed class PropertyChangedImpl : INotifyPropertyChanged
{
private readonly object _instance;
public PropertyChangedImpl(object instance)
{
if (instance == null) throw new ArgumentNullException("instance");
_instance = instance;
}
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName)
{
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
var handler = PropertyChanged as PropertyChangedEventHandler;
if (handler != null) handler(_instance, new PropertyChangedEventArgs(propertyName));
}
}
}
Затем у меня есть пара классов (пользователь и адрес), которые реализуют [NotifyPropertyChanged]. Это работает нормально. Но я хочу, чтобы при изменении дочернего объекта (в моем примере адреса) родительский объект получал уведомление (в моем случае пользователь). Можно ли расширить этот код, чтобы он автоматически создавал прослушиватели для родительских объектов, которые прослушивают изменения в своих дочерних объектах?