private void SetCacheFlagInAncestry(DependencyObject element, bool newValue, DeferredElementTreeState treeState, bool shortCircuit, bool setOriginCacheFlag) { UIElement uie; ContentElement ce; UIElement3D uie3D; CastElement(element, out uie, out ce, out uie3D); bool isFlagSet = IsFlagSet(uie, ce, uie3D, FlagCache); bool isFlagOriginCacheSet = (setOriginCacheFlag ? IsFlagSet(uie, ce, uie3D, (newValue ? FlagNewOriginCache : FlagOldOriginCache)) : false); // If the cache flag value is undergoing change, record it and // propagate the change to the ancestors. if ((newValue != isFlagSet) || (setOriginCacheFlag && !isFlagOriginCacheSet) || !shortCircuit) { if (newValue != isFlagSet) { SetFlag(uie, ce, uie3D, FlagCache, newValue); // NOTE: we toggle the changed flag instead of setting it so that that way common // ancestors show resultant unchanged and do not receive any change notification. SetFlag(uie, ce, uie3D, FlagChanged, !IsFlagSet(uie, ce, uie3D, FlagChanged)); } if (setOriginCacheFlag && !isFlagOriginCacheSet) { SetFlag(uie, ce, uie3D, (newValue ? FlagNewOriginCache : FlagOldOriginCache), true); } // Check for block reverse inheritance flag, elements like popup want to set this. if (BlockReverseInheritance(uie, ce, uie3D)) { return; } // Propagate the flag up the visual and logical trees. Note our // minimal optimization check to avoid walking both the core // and logical parents if they are the same. { DependencyObject coreParent = DeferredElementTreeState.GetInputElementParent(element, treeState); DependencyObject logicalParent = DeferredElementTreeState.GetLogicalParent(element, treeState); if (coreParent != null) { SetCacheFlagInAncestry(coreParent, newValue, treeState, shortCircuit, setOriginCacheFlag); } if (logicalParent != null && logicalParent != coreParent) { SetCacheFlagInAncestry(logicalParent, newValue, treeState, shortCircuit, setOriginCacheFlag); } } } }
private void FirePropertyChangeInAncestry(DependencyObject element, bool oldValue, DeferredElementTreeState treeState, Action <DependencyObject, bool> originChangedAction) { UIElement uie; ContentElement ce; UIElement3D uie3D; CastElement(element, out uie, out ce, out uie3D); bool flagChanged = IsFlagSet(uie, ce, uie3D, FlagChanged); bool isFlagOldOriginCacheSet = ((FlagOldOriginCache == CoreFlags.None) ? false : IsFlagSet(uie, ce, uie3D, FlagOldOriginCache)); bool isFlagNewOriginCacheSet = ((FlagNewOriginCache == CoreFlags.None) ? false : IsFlagSet(uie, ce, uie3D, FlagNewOriginCache)); if (flagChanged || isFlagOldOriginCacheSet || isFlagNewOriginCacheSet) { if (flagChanged) { // if FlagChanged bit is set, then the value has changed effectively // after considering all the origins. Hence change the property value // and fire notifications. SetFlag(uie, ce, uie3D, FlagChanged, false); if (oldValue) { element.ClearValue(FlagKey); } else { element.SetValue(FlagKey, true); } FireNotifications(uie, ce, uie3D, oldValue); } if (isFlagOldOriginCacheSet || isFlagNewOriginCacheSet) { SetFlag(uie, ce, uie3D, FlagOldOriginCache, false); SetFlag(uie, ce, uie3D, FlagNewOriginCache, false); if (isFlagOldOriginCacheSet != isFlagNewOriginCacheSet) { // if either FlagOldOriginCache or FlagNewOriginCache // are set, then the origin change has affected this node // and hence originChangedAction should be executed. Debug.Assert(originChangedAction != null); originChangedAction(element, oldValue); } } // Check for block reverse inheritance flag, elements like popup want to set this. if (BlockReverseInheritance(uie, ce, uie3D)) { return; } // Call FirePropertyChange up the visual and logical trees. // Note our minimal optimization check to avoid walking both // the core and logical parents if they are the same. { DependencyObject coreParent = DeferredElementTreeState.GetInputElementParent(element, treeState); DependencyObject logicalParent = DeferredElementTreeState.GetLogicalParent(element, treeState); if (coreParent != null) { FirePropertyChangeInAncestry(coreParent, oldValue, treeState, originChangedAction); } if (logicalParent != null && logicalParent != coreParent) { FirePropertyChangeInAncestry(logicalParent, oldValue, treeState, originChangedAction); } } } }