public SingleTypePropertyCache(INotifyPropertyChanged singleTypedPropertyNotifier, object singleTypedPropertiesOwner, IEqualityComparer <PropertyType>?propertyValueEqualityComparer) { singleTypedPropertyNotifier = singleTypedPropertyNotifier ?? throw new ArgumentNullException(nameof(singleTypedPropertyNotifier)); singleTypedPropertiesOwner = singleTypedPropertiesOwner ?? throw new ArgumentNullException(nameof(singleTypedPropertiesOwner)); propertyValueEqualityComparer = propertyValueEqualityComparer ?? EqualityComparer <PropertyType> .Default; TrackingPropertyType = typeof(PropertyType); var propertyTypeInfo = TrackingPropertyType.GetTypeInfo(); if (propertyTypeInfo.IsValueType) { propertyComparisonMode = PropertyComparisonMode.ValueType; } else { propertyComparisonMode = PropertyComparisonMode.ReferenceType; } cachedPropertyValues = new Dictionary <string, PropertyType>(); CachedPropertyValues = new ReadOnlyDictionary <string, PropertyType>(cachedPropertyValues); VariableInfoDescriptor = new VariableInfoDescriptor(); TrackingPropertyDefaultValue = default; CanHandleDefaultValue = true; SingleTypedPropertyNotifier = singleTypedPropertyNotifier; SingleTypedPropertyNotifier.PropertyChanged += SingleTypePropertyNotifier_PropertyChanged; SingleTypedPropertiesOwner = singleTypedPropertiesOwner; SingleTypedPropertiesOwnerType = singleTypedPropertiesOwner.GetType(); PropertyValueEqualityComparer = propertyValueEqualityComparer; }
/// <summary> /// We calling it, you are forcing a property being tracked. /// </summary> /// <param name="propertyName"></param> public void SingleTypePropertyNotifierPropertyChanged(string propertyName) { VariableInfoDescriptor.Flags |= BindingFlags.NonPublic | BindingFlags.GetProperty | BindingFlags.GetField; var propertyMember = SingleTypedPropertiesOwnerType.GetVariableMember(propertyName, VariableInfoDescriptor); // There is no member that can be handled, so we return. if (propertyMember == null) { return; } var propertyType = propertyMember.GetVariableType(); PropertyType typedPropertyValue; var propertyValue = propertyMember.GetValue(SingleTypedPropertiesOwner); // We want to assign property value (object) to typed property value. if (propertyComparisonMode == PropertyComparisonMode.ValueType && TrackingPropertyType == propertyType || propertyComparisonMode == PropertyComparisonMode.ReferenceType && TrackingPropertyType.IsAssignableFrom(propertyType)) { typedPropertyValue = (PropertyType)propertyValue; } else { return; // The type of the property does not meet the requirements, so we skip the property } var isPropertNameTracked = cachedPropertyValues.ContainsKey(propertyName); // We want to abort if tracking property name is untracked and tracking property value is equals default/null. if (!isPropertNameTracked && CanHandleDefaultValue && PropertyValueEqualityComparer.Equals(typedPropertyValue !, TrackingPropertyDefaultValue !)) { return; } void trackPropertyViaArgs(PropertyCachedEventArgs <PropertyType> args) { cachedPropertyValues.Add(propertyName, args.PropertyValue !); OnPropertyCacheAdded(args); } void trackProperty(PropertyType uncachedProperty) { var args = new PropertyCachedEventArgs <PropertyType>(propertyName, uncachedProperty); trackPropertyViaArgs(args); } void untrackProperty(PropertyType cachedProperty, bool isRetrack) { cachedPropertyValues.Remove(propertyName); if (isRetrack && CanSkipPropertyRemovedEventInvocationWhenRetracking) { return; } var args = new PropertyCacheRemovedEventArgs <PropertyType>(propertyName, cachedProperty); OnPropertyCacheRemoved(args); } void retrackProperty(PropertyType cachedProperty, PropertyType uncachedProperty) { untrackProperty(cachedProperty, true); var args = new PropertyCachedEventArgs <PropertyType>(propertyName, uncachedProperty, cachedProperty); trackPropertyViaArgs(args); } if (!isPropertNameTracked) { var args = new PropertyCachingEventArgs <PropertyType>(propertyName, typedPropertyValue); OnPropertyCacheAdding(args); if (!args.CanTrackProperty) { return; } // Add new subscription trackProperty(typedPropertyValue !); } else { var cachedProperty = cachedPropertyValues[propertyName]; if (CanHandleDefaultValue && PropertyValueEqualityComparer.Equals(typedPropertyValue !, TrackingPropertyDefaultValue !)) { untrackProperty(cachedProperty, false); }