/// <summary> Implements the functionality documented in the other overloads. </summary> private static void Bind(INotifyPropertyChanged source, string propertyName, string propertyOnPropertyName, PropertyChangedEventHandler handler, object defaultValue, Type propertyOnPropertyType) { Contract.Requires(source != null); Contract.Requires(handler != null); Contract.Requires(source.GetType().GetProperty(propertyName) != null); var sourceProperty = GetProperty(source.GetType(), propertyName); var sourcePropertyType = GetPropertyType(source.GetType(), propertyName); Contract.Requires(sourcePropertyType.Implements(typeof(INotifyPropertyChanged)), $"The property on the source must implement '{nameof(INotifyPropertyChanged)}'"); Contract.Requires(GetPropertyType(sourcePropertyType, propertyOnPropertyName) != null, $"Property '{propertyName}' was not found on type '{sourcePropertyType.Name}'"); Contract.Requires(propertyOnPropertyType.IsAssignableFrom(GetPropertyType(sourcePropertyType, propertyOnPropertyName))); Contract.Requires(propertyOnPropertyType.IsInstanceOfType(defaultValue) || (ReferenceEquals(defaultValue, null) && !propertyOnPropertyType.IsValueType)); handler = handler.FilterOn(propertyOnPropertyName); PropertyChangedEventHandler onSourcePropertyChanged = (sender, eventArg) => { Contract.Requires(eventArg is IPropertyMutatedEventArgs); var e = (IPropertyMutatedEventArgs)eventArg; var oldSource = (INotifyPropertyChanged)e.OldValue; if (oldSource != null) { oldSource.PropertyChanged -= handler; } var newSource = (INotifyPropertyChanged)e.NewValue; if (newSource != null) { newSource.PropertyChanged += handler; } var oldValue = GetPropertyValue(oldSource, propertyOnPropertyName, defaultValue: defaultValue); var newValue = GetPropertyValue(newSource, propertyOnPropertyName, defaultValue: defaultValue); if (!Equals(oldValue, newValue)) // uses virtual method oldValue.Equals(object) { handler(newSource ?? oldSource, PropertyMutatedEventArgsExtensions.Create(propertyOnPropertyName, propertyOnPropertyType, oldValue, newValue)); } }; source.PropertyChanged += onSourcePropertyChanged.FilterOn(propertyName); object currentValue = sourceProperty.GetValue(source); // onSourcePropertyChanged is invoked regardless of whether currentValue equals sourcePropertyType.GetDefault() // because it hooks the handler onto currentValue.PropertyChange onSourcePropertyChanged(source, PropertyMutatedEventArgsExtensions.Create(propertyName, sourcePropertyType, sourcePropertyType.GetDefault(), currentValue)); }