private void UnHookNotifyChildPropertyChangedHandler(NotifyChildPropertyChangedEventHandlerDescriptor handlerDescriptor) { object currentValue = handlerDescriptor.Reference.Target; if (currentValue != null) { NotifyPropertyChangedAccessor.RemoveChildPropertyChangedHandler(currentValue, handlerDescriptor.Handler); } }
private void HookNotifyChildPropertyChangedHandler(object instance, string locationName) { object currentValue = instance as INotifyPropertyChanged; if (currentValue != null && instrumentedTypes.GetOrAdd(currentValue.GetType(), type => type.IsDefined(typeof(NotifyPropertyChangedAttribute), true))) { string locationNameClosure = locationName; NotifyChildPropertyChangedEventHandlerDescriptor handlerDescriptor = new NotifyChildPropertyChangedEventHandlerDescriptor( currentValue, (_, a) => this.NotifyChildPropertyChangedEventHandler(locationNameClosure, a)); this.notifyChildPropertyChangedHandlers.AddOrUpdate(locationNameClosure, handlerDescriptor); NotifyPropertyChangedAccessor.AddChildPropertyChangedHandler(currentValue, handlerDescriptor.Handler); } }
private static void RaisePropertyChangesInternal( ChangedPropertiesAccumulator accumulator, bool raiseChildPropertyChanges, Func <WeakPropertyDescriptor, bool> propertySelectorPredicate) { areEventsFiring = true; accumulator.Compact(); List <WeakPropertyDescriptor> objectsToRaisePropertyChanged; int loopCount = 0; Dictionary <WeakPropertyDescriptor, int> raiseCounts = accumulator.ToDictionary(w => w, w => 0); do { objectsToRaisePropertyChanged = accumulator.Where(propertySelectorPredicate).ToList(); foreach (WeakPropertyDescriptor w in objectsToRaisePropertyChanged) { int raiseCount = raiseCounts.GetOrCreate(w, () => 0); //INPC handler may raise INPC again and process some of our events; //we're working on accumulator copy, so only way to know it is to have a flag on the descriptor if (w.Processed || raiseChildPropertyChanges ? raiseCount > 0 : raiseCount > 1) { w.Processed = true; continue; } w.Processed = true; accumulator.Remove(w); object cpc = w.Instance.Target; if (cpc != null) //Target may not be alive any more { raiseCounts[w]++; if (raiseChildPropertyChanges) { NotifyPropertyChangedAccessor.RaiseChildPropertyChanged(cpc, w.PropertyPath); } else { NotifyPropertyChangedAccessor.RaisePropertyChanged(cpc, w.PropertyPath); } } } //Notifications may cause generation of new notifications, continue until there is nothing left to raise }while (objectsToRaisePropertyChanged.Count > 0 && ++loopCount <= 32); areEventsFiring = false; //TODO: Verify the loop above will always stop. //If there's a risk it won't, call RaiseChildPropertyChanged from NPCAttribute.ChildPropertyChangedEventHandler to bubble up CNPC notifications //(this may lead to a lot of unneccessary recursion, however, and a lot of continuations on w.Processed check above) // if we encounter infinite loop generate meaningful exception for bug report. if (loopCount == 32) { throw new NotifyPropertyChangedAlgorithmInfiniteLoop("Encountered infinite loop while raising PropertyChanged events"); } }
public void HookPropertyChangedHandler() { NotifyPropertyChangedAccessor.AddPropertyChangedHandler(this.instance, this.OnPropertyChanged); }