Example #1
0
        /// <summary>
        ///     Callback on visiting each node in the descendency 
        ///     during an inheritable property change
        /// </summary>
        private static bool OnInheritablePropertyChanged(
            DependencyObject              d, 
            InheritablePropertyChangeInfo info)
        { 
            Debug.Assert(d != null, "Must have non-null current node"); 

            DependencyProperty dp = info.Property; 
            EffectiveValueEntry oldEntry = info.OldEntry;
            EffectiveValueEntry newEntry = info.NewEntry;

            InheritanceBehavior inheritanceBehavior; 
            bool inheritanceNode = IsInheritanceNode(d, dp, out inheritanceBehavior);
            bool isForceInheritedProperty = IsForceInheritedProperty(dp); 
 
            // Note that if a node is marked SkipNext means it hasn't acquired any values from its parent and
            // hence we do not need to invalidate this node or any of its descendents. However if a node is 
            // marked SkipNow then this node might have acquired values from its parent but none of its
            // descendents would. Hence in this case we process the current node but omit all of its descendents.
            if (inheritanceNode && (!SkipNext(inheritanceBehavior) || isForceInheritedProperty))
            { 
                PropertyMetadata metadata = dp.GetMetadata(d);
                EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex); 
 
                // Found an inheritance node
                if (!d.IsSelfInheritanceParent) 
                {
                    DependencyObject parent = FrameworkElement.GetFrameworkParent(d);
                    InheritanceBehavior parentInheritanceBehavior = InheritanceBehavior.Default;
 
                    if (parent != null)
                    { 
                        FrameworkObject parentFO = new FrameworkObject(parent, true); 
                        parentInheritanceBehavior = parentFO.InheritanceBehavior;
                    } 

                    if (!SkipNext(inheritanceBehavior) && !SkipNow(parentInheritanceBehavior))
                    {
                        // Synchronize InheritanceParent 
                        d.SynchronizeInheritanceParent(parent);
                    } 
 
                    // What should the oldValueSource on the child be?
                    // When the oldValue on the parent was default it 
                    // means that the child also used its own default
                    // and did not inherit from the parent. However
                    // when the value on the parent was non-default
                    // it means that the child inherited it. 
                    // Note that the oldValueSource on inheritablePropertyChangedData
                    // is actually the parent's oldValueSource 
 
                    if (oldEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown)
                    { 
                        // we use an empty EffectiveValueEntry as a signal that the old entry was the default value
                        oldEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(d, dp));
                    }
                } 
                else
                { 
                    oldEntry = d.GetValueEntry( 
                                        entryIndex,
                                        dp, 
                                        metadata,
                                        RequestFlags.RawEntry);
                 }
 
                // If the oldValueSource is of lower precedence than Inheritance
                // only then do we need to Invalidate the property 
                if (BaseValueSourceInternal.Inherited >= oldEntry.BaseValueSourceInternal) 
                {
                    // Since we do not hold a cache of the oldValue we need to supply one 
                    // in order to correctly fire the change notification
                    return (d.UpdateEffectiveValue(
                            entryIndex,
                            dp, 
                            metadata,
                            oldEntry, 
                            ref newEntry, 
                            false /* coerceWithDeferredReference */,
                            false /* coerceWithCurrentValue */, 
                            OperationType.Inherit)
                        & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden))
                        == UpdateResult.ValueChanged;
                    // return false if either the value didn't change or 
                    // it changed because the inherited value was overridden by coercion or animation.
                } 
                else if (isForceInheritedProperty) 
                {
                    // IsCoerced == true && value == UnsetValue indicates that we need to re-coerce this value 
                    newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced);

                    // Re-coerce a force inherited property because it's coersion depends on treeness
                    return (d.UpdateEffectiveValue( 
                            d.LookupEntry(dp.GlobalIndex),
                            dp, 
                            metadata, 
                            oldEntry,
                            ref newEntry, 
                            false /* coerceWithDeferredReference */,
                            false /* coerceWithCurrentValue */,
                            OperationType.Inherit)
                        & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden)) 
                        == UpdateResult.ValueChanged;
                    // return false if either the value didn't change or 
                    // it changed because the inherited value was overridden by coercion or animation. 
                }
                else 
                {
                    return false;
                }
            } 

            // Do not continue walk down subtree if the walk was forced to stop 
            // (due to separated trees) 
            return (inheritanceBehavior == InheritanceBehavior.Default || isForceInheritedProperty);
        } 
        //
        //  This method
        //  1. Is called from AncestorChange InvalidateTree.
        //  2. It is used to create the InheritableProperties on the given node.
        //  3. It also accumulates oldValues for the inheritable properties that are about to be invalidated
        //
        internal FrugalObjectList<DependencyProperty> CreateParentInheritableProperties(
            DependencyObject                         d,
            DependencyObject                         parent,
            bool                                     isAddOperation)
        {
            Debug.Assert(d != null, "Must have non-null current node");
            
            if (parent == null)
            {
                return new FrugalObjectList<DependencyProperty>(0);
            }

            DependencyObjectType treeObjDOT = d.DependencyObjectType;

            // See if we have a cached value.
            EffectiveValueEntry[] parentEffectiveValues = null;
            uint parentEffectiveValuesCount = 0;
            uint inheritablePropertiesCount = 0;

            // If inheritable properties aren't cached on you then use the effective
            // values cache on the parent to discover those inherited properties that
            // may need to be invalidated on the children nodes.
            if (!parent.IsSelfInheritanceParent)
            {
                DependencyObject inheritanceParent = parent.InheritanceParent;
                if (inheritanceParent != null)
                {
                    parentEffectiveValues = inheritanceParent.EffectiveValues;
                    parentEffectiveValuesCount = inheritanceParent.EffectiveValuesCount;
                    inheritablePropertiesCount = inheritanceParent.InheritableEffectiveValuesCount;
                }
            }
            else
            {
                parentEffectiveValues = parent.EffectiveValues;
                parentEffectiveValuesCount = parent.EffectiveValuesCount;
                inheritablePropertiesCount = parent.InheritableEffectiveValuesCount;
            }

            FrugalObjectList<DependencyProperty> inheritableProperties = new FrugalObjectList<DependencyProperty>((int) inheritablePropertiesCount);

            if (inheritablePropertiesCount == 0)
            {
                return inheritableProperties;
            }

            _rootInheritableValues = new InheritablePropertyChangeInfo[(int) inheritablePropertiesCount];
            int inheritableIndex = 0;

            FrameworkObject foParent = new FrameworkObject(parent);
            
            for (uint i=0; i<parentEffectiveValuesCount; i++)
            {
                // Add all the inheritable properties from the effectiveValues
                // cache to the TreeStateCache on the parent
                EffectiveValueEntry entry = parentEffectiveValues[i];
                DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[entry.PropertyIndex];

                // There are UncommonFields also stored in the EffectiveValues cache. We need to exclude those.
                if ((dp != null) && dp.IsPotentiallyInherited)
                {
                    PropertyMetadata metadata = dp.GetMetadata(parent.DependencyObjectType);
                    if (metadata != null && metadata.IsInherited)
                    {
                        Debug.Assert(!inheritableProperties.Contains(dp), "EffectiveValues cache must not contains duplicate entries for the same DP");

                        FrameworkPropertyMetadata fMetadata = (FrameworkPropertyMetadata)metadata;

                        // Children do not need to inherit properties across a tree boundary 
                        // unless the property is set to override this behavior.

                        if (!TreeWalkHelper.SkipNow(foParent.InheritanceBehavior) || fMetadata.OverridesInheritanceBehavior)
                        {
                            inheritableProperties.Add(dp);

                            EffectiveValueEntry oldEntry;
                            EffectiveValueEntry newEntry;

                            oldEntry = d.GetValueEntry(
                                        d.LookupEntry(dp.GlobalIndex),
                                        dp,
                                        dp.GetMetadata(treeObjDOT),
                                        RequestFlags.DeferredReferences);

                            if (isAddOperation)
                            {
                                // set up the new value
                                newEntry = entry;

                                if ((newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Default) || newEntry.HasModifiers)
                                {                        
                                    newEntry = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
                                    newEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
                                }                        
                            }
                            else
                            {
                                newEntry = new EffectiveValueEntry();
                            }

                            
                            _rootInheritableValues[inheritableIndex++] = 
                                        new InheritablePropertyChangeInfo(d, dp, oldEntry, newEntry);

                            if (inheritablePropertiesCount == inheritableIndex)
                            {
                                // no more inheritable properties, bail early
                                break;
                            }
                        }
                    }
                }
            }

            return inheritableProperties;
        }
Example #3
0
        /// <summary> 
        ///     Invalidate this property if 
        ///     - It is not locally set and
        ///     - It is not acquired from a style/template 
        /// </summary>
        private static bool InvalidateTreeDependentProperty(
            TreeChangeInfo              info,
            DependencyObject            d, 
        ref FrameworkObject             fo,
            DependencyProperty          dp, 
            FrameworkPropertyMetadata   fMetadata, 
            Style                       selfStyle,
            Style                       selfThemeStyle, 
            ref ChildRecord             childRecord,
            bool                        isChildRecordValid,
            bool                        hasStyleChanged,
            bool                        isSelfInheritanceParent) 
        {
            Debug.Assert(d != null, "Must have non-null current node"); 
 
            // This must be an inherited dependency property
            Debug.Assert(fMetadata.IsInherited == true, "This must be an inherited dependency property"); 

            // Children do not need to inherit properties across a tree boundary
            // unless the property is set to override this behavior.
 
            if (!SkipNext(fo.InheritanceBehavior) || fMetadata.OverridesInheritanceBehavior)
            { 
                InheritablePropertyChangeInfo rootInfo = info.GetRootInheritableValue(dp); 

                EffectiveValueEntry oldEntry = rootInfo.OldEntry; 
                EffectiveValueEntry newEntry = info.IsAddOperation ? rootInfo.NewEntry : new EffectiveValueEntry(dp, BaseValueSourceInternal.Inherited);

                bool isForceInheritedProperty = IsForceInheritedProperty(dp);
 
                if (d != info.Root)
                { 
                    if (isSelfInheritanceParent) 
                    {
                        oldEntry = d.GetValueEntry( 
                                d.LookupEntry(dp.GlobalIndex),
                                dp,
                                fMetadata,
                                RequestFlags.DeferredReferences); 
                    }
                    else 
                    { 
                        oldEntry = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
                        oldEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited; 
                    }
                }

                OperationType operationType = info.IsAddOperation ? OperationType.AddChild : OperationType.RemoveChild; 
                if (BaseValueSourceInternal.Inherited >= oldEntry.BaseValueSourceInternal)
                { 
                    // If the oldValueSource is of lower precedence than Inheritance 
                    // only then do we need to Invalidate the property. Examples of
                    // values with higher precedence are those that are locally set 
                    // or set via a style/template.
                    return (d.UpdateEffectiveValue(
                                d.LookupEntry(dp.GlobalIndex),
                                dp, 
                                fMetadata,
                                oldEntry, 
                                ref newEntry, 
                                false /* coerceWithDeferredReference */,
                                false /* coerceWithCurrentValue */, 
                                operationType)
                            & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden))
                            == UpdateResult.ValueChanged;
                        // return false if either the value didn't change or 
                        // it changed because the inherited value was overridden by coercion or animation.
                } 
                else if (isForceInheritedProperty) 
                {
                    // IsCoerced == true && value == UnsetValue indicates that we need to re-coerce this value 
                    newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced);

                    // Re-coerce a force inherited property because it's coersion depends on treeness
                    return (d.UpdateEffectiveValue( 
                                d.LookupEntry(dp.GlobalIndex),
                                dp, 
                                fMetadata, 
                                oldEntry,
                                ref newEntry, 
                                false /* coerceWithDeferredReference */,
                                false /* coerceWithCurrentValue */,
                                operationType)
                            & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden)) 
                            == UpdateResult.ValueChanged;
                        // return false if either the value didn't change or 
                        // it changed because the inherited value was overridden by coercion or animation. 
                }
            } 

            return false;
        }
Example #4
0
        // 
        //  This method
        //  1. Merges the inheritable properties from the parent into the EffectiveValues store on self
        //
        private void MergeInheritableProperties(DependencyObject inheritanceParent) 
        {
            Debug.Assert(inheritanceParent != null, "Must have inheritanceParent"); 
            Debug.Assert(inheritanceParent.IsSelfInheritanceParent, "An inheritanceParent should always be one that has all the inheritable properties cached on self"); 

            EffectiveValueEntry[] parentEffectiveValues = inheritanceParent.EffectiveValues; 
            uint parentEffectiveValuesCount = inheritanceParent.EffectiveValuesCount;

            for (uint i=0; i<parentEffectiveValuesCount; i++)
            { 
                EffectiveValueEntry entry = parentEffectiveValues[i];
                DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[entry.PropertyIndex]; 
 
                // There are UncommonFields also stored in the EffectiveValues cache. We need to exclude those.
                if (dp != null) 
                {
                    PropertyMetadata metadata = dp.GetMetadata(DependencyObjectType);
                    if (metadata.IsInherited)
                    { 
                        object value = inheritanceParent.GetValueEntry(
                                            new EntryIndex(i), 
                                            dp, 
                                            metadata,
                                            RequestFlags.SkipDefault | RequestFlags.DeferredReferences).Value; 
                        if (value != DependencyProperty.UnsetValue)
                        {
                            EntryIndex entryIndex = LookupEntry(dp.GlobalIndex);
 
                            SetEffectiveValue(entryIndex, dp, dp.GlobalIndex, metadata, value, BaseValueSourceInternal.Inherited);
                        } 
                    } 
                }
            } 
        }
Example #5
0
        private static bool DefaultFreezeValueCallback( 
            DependencyObject d,
            DependencyProperty dp, 
            EntryIndex entryIndex, 
            PropertyMetadata metadata,
            bool isChecking) 
        {
            // The expression check only needs to be done when isChecking is true
            // because if we return false here the Freeze() call will fail.
            if (isChecking) 
            {
                if (d.HasExpression(entryIndex, dp)) 
                { 
                    if (TraceFreezable.IsEnabled)
                    { 
                        TraceFreezable.Trace(
                            TraceEventType.Warning,
                            TraceFreezable.UnableToFreezeExpression,
                            d, 
                            dp,
                            dp.OwnerType); 
                    } 

                    return false; 
                }
            }

            if (!dp.IsValueType) 
            {
                object value = 
                    d.GetValueEntry( 
                        entryIndex,
                        dp, 
                        metadata,
                        RequestFlags.FullyResolved).Value;

                if (value != null) 
                {
                    Freezable valueAsFreezable = value as Freezable; 
 
                    if (valueAsFreezable != null)
                    { 
                        if (!valueAsFreezable.Freeze(isChecking))
                        {
                            if (TraceFreezable.IsEnabled)
                            { 
                                TraceFreezable.Trace(
                                    TraceEventType.Warning, 
                                    TraceFreezable.UnableToFreezeFreezableSubProperty, 
                                    d,
                                    dp, 
                                    dp.OwnerType);
                            }

                            return false; 
                        }
                    } 
                    else  // not a Freezable 
                    {
                        DispatcherObject valueAsDispatcherObject = value as DispatcherObject; 

                        if (valueAsDispatcherObject != null)
                        {
                            if (valueAsDispatcherObject.Dispatcher == null) 
                            {
                                // The property is a free-threaded DispatcherObject; since it's 
                                // already free-threaded it doesn't prevent this Freezable from 
                                // becoming free-threaded too.
                                // It is up to the creator of this type to ensure that the 
                                // DispatcherObject is actually immutable
                            }
                            else
                            { 
                                // The value of this property derives from DispatcherObject and
                                // has thread affinity; return false. 
 
                                if (TraceFreezable.IsEnabled)
                                { 
                                    TraceFreezable.Trace(
                                        TraceEventType.Warning,
                                        TraceFreezable.UnableToFreezeDispatcherObjectWithThreadAffinity,
                                        d, 
                                        dp,
                                        dp.OwnerType, 
                                        valueAsDispatcherObject ); 
                                }
 
                                return false;
                            }
                        }
 
                        // The property isn't a DispatcherObject.  It may be immutable (such as a string)
                        // or the user may have made it thread-safe.  It's up to the creator of the type to 
                        // do the right thing; we return true as an extensibility point. 
                    }
                } 
            }

            return true;
        } 
        // Consider the markup <Element A="x" B="{Binding...}"/>, and suppose
        // that setting A (to x) causes the element to assign a new value y for B. 
        // (Lots of examples of this:  e.g. setting Selector.SelectedIndex causes
        // Selector to assign a new value to Selector.SelectedItem.)  The end
        // result depends on what order the assignments are done.  If A=x happens
        // first, it assigns y to B but that is later overwritten by the 
        // data-bound value z;  if B happens first, the binding is installed and
        // produces the value z, then the assignment A=x sends the value y through 
        // the binding (if it's two-way) to the data source.  In other words, you 
        // end up with z in the first case, but y in the second, and only the
        // second case changes the data source. 
        //
        // The order of assignment (during initialization) is out of the user's
        // control, especially when the element is part of a template instance.
        // It can depend on the order in which static constructors are called, 
        // which can vary depending on which elements appear first in the markup.
        // To mitigate this mysterious behavior, the following code attempts to 
        // detect the situation and make it appear as if the binding always 
        // happened first.
        internal bool ShouldUpdateWithCurrentValue(DependencyObject target, out object currentValue) 
        {
            if (IsReflective)
            {
                // the bad situation only arises during initialization. After that, 
                // the order of property assignments is determined by the app's
                // normal control flow.  Unfortunately, we can only detect 
                // initialization for framework elements;  fortunately, this covers 
                // all the known cases of the bad situation
                FrameworkObject fo = new FrameworkObject(target); 
                if (!fo.IsInitialized)
                {
                    // if the target property (B) already has a changed value (y),
                    // we're in the bad situation and should propagate y back to 
                    // the data source
                    DependencyProperty dp = TargetProperty; 
                    EntryIndex entryIndex = target.LookupEntry(dp.GlobalIndex); 
                    if (entryIndex.Found)
                    { 
                        EffectiveValueEntry entry = target.GetValueEntry(entryIndex, dp, null, RequestFlags.RawEntry);
                        if (entry.IsCoercedWithCurrentValue)
                        {
                            currentValue = entry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 
                            if (entry.IsDeferredReference)
                            { 
                                DeferredReference deferredReference = (DeferredReference)currentValue; 
                                currentValue = deferredReference.GetValue(entry.BaseValueSourceInternal);
                            } 
                            return true;
                        }
                    }
                } 
            }
 
            currentValue = null; 
            return false;
        } 
Example #7
0
        /// <summary>
        ///     Callback on visiting each node in the descendency
        ///     during an inheritable property change
        /// </summary>
        private static bool OnInheritablePropertyChanged(
            DependencyObject              d,
            InheritablePropertyChangeInfo info,
            bool                          visitedViaVisualTree)
        {
            Debug.Assert(d != null, "Must have non-null current node");

            DependencyProperty dp = info.Property;
            EffectiveValueEntry oldEntry = info.OldEntry;
            EffectiveValueEntry newEntry = info.NewEntry;

            InheritanceBehavior inheritanceBehavior;
            bool inheritanceNode = IsInheritanceNode(d, dp, out inheritanceBehavior);
            bool isForceInheritedProperty = IsForceInheritedProperty(dp);

            // Note that if a node is marked SkipNext means it hasn't acquired any values from its parent and
            // hence we do not need to invalidate this node or any of its descendents. However if a node is
            // marked SkipNow then this node might have acquired values from its parent but none of its
            // descendents would. Hence in this case we process the current node but omit all of its descendents.
            if (inheritanceNode && (!SkipNext(inheritanceBehavior) || isForceInheritedProperty))
            {
                PropertyMetadata metadata = dp.GetMetadata(d);
                EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex);

                // Found an inheritance node
                if (!d.IsSelfInheritanceParent)
                {
                    DependencyObject parent = FrameworkElement.GetFrameworkParent(d);
                    InheritanceBehavior parentInheritanceBehavior = InheritanceBehavior.Default;

                    if (parent != null)
                    {
                        FrameworkObject parentFO = new FrameworkObject(parent, true);
                        parentInheritanceBehavior = parentFO.InheritanceBehavior;
                    }

                    if (!SkipNext(inheritanceBehavior) && !SkipNow(parentInheritanceBehavior))
                    {
                        // Synchronize InheritanceParent
                        d.SynchronizeInheritanceParent(parent);
                    }

                    // What should the oldValueSource on the child be?
                    // When the oldValue on the parent was default it
                    // means that the child also used its own default
                    // and did not inherit from the parent. However
                    // when the value on the parent was non-default
                    // it means that the child inherited it.
                    // Note that the oldValueSource on inheritablePropertyChangedData
                    // is actually the parent's oldValueSource

                    if (oldEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown)
                    {
                        // we use an empty EffectiveValueEntry as a signal that the old entry was the default value
                        oldEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(d, dp));
                    }
                }
                else
                {
                    oldEntry = d.GetValueEntry(
                                        entryIndex,
                                        dp,
                                        metadata,
                                        RequestFlags.RawEntry);
                 }

                // If the oldValueSource is of lower precedence than Inheritance
                // only then do we need to Invalidate the property
                if (BaseValueSourceInternal.Inherited >= oldEntry.BaseValueSourceInternal)
                {
                    if (visitedViaVisualTree && FrameworkElement.DType.IsInstanceOfType(d))
                    {
                        DependencyObject logicalParent = LogicalTreeHelper.GetParent(d);
                        if (logicalParent != null)
                        {
                            DependencyObject visualParent = VisualTreeHelper.GetParent(d);
                            if (visualParent != null && visualParent != logicalParent)
                            {
                                // Consider the following logical tree configuration. In this case we want 
                                // to RibbonToggleButton to pick up the new DataContext flowing in from 
                                // the Window.
                                //
                                // Window (info.RootElement)
                                //   ...
                                //   RibbonGroup (IsCollapsed)
                                //      RibbonControl (only in visual tree)
                                //          RibbonToggleButton
                                //
                                // Consider the following logical tree configuration. In this case we do not 
                                // want to RibbonToggleButton to change its DataContext because the changes 
                                // are only within the visual tree.
                                //
                                // Window 
                                //   ...
                                //   RibbonGroup (IsCollapsed)
                                //      RibbonControl (only in visual tree) (info.RootElement)
                                //          RibbonToggleButton
                                //
                                // Saying it another way, the RibbonToggleButton in the above case belongs in a 
                                // different logical tree than the one that the current invalidation storm begun.
                                //
                                // Any change in an inheritable property begins an invalidation storm using the 
                                // DescendentsWalker and configures it to first traverse the logical children 
                                // and then visual children. Also nodes that have previously been visited via the 
                                // logical tree do not get visited again through the visual tree. I use this very 
                                // behavior as the basis for detecting nodes such as RibbonToggleButton. If the 
                                // RibbonToggleButton is being visisted for the first time via the visual tree then 
                                // the invalidation storm did not include its logical parent. And therefore the 
                                // RibbonToggleButton can early out of this storm.
                                return false;
                            }
                        }
                    }
                    
                    // Since we do not hold a cache of the oldValue we need to supply one
                    // in order to correctly fire the change notification
                    return (d.UpdateEffectiveValue(
                            entryIndex,
                            dp,
                            metadata,
                            oldEntry,
                            ref newEntry,
                            false /* coerceWithDeferredReference */,
                            false /* coerceWithCurrentValue */,
                            OperationType.Inherit)
                        & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden))
                        == UpdateResult.ValueChanged;
                    // return false if either the value didn't change or
                    // it changed because the inherited value was overridden by coercion or animation.
                }
                else if (isForceInheritedProperty)
                {
                    // IsCoerced == true && value == UnsetValue indicates that we need to re-coerce this value
                    newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced);

                    // Re-coerce a force inherited property because it's coersion depends on treeness
                    return (d.UpdateEffectiveValue(
                            d.LookupEntry(dp.GlobalIndex),
                            dp,
                            metadata,
                            oldEntry,
                            ref newEntry,
                            false /* coerceWithDeferredReference */,
                            false /* coerceWithCurrentValue */,
                            OperationType.Inherit)
                        & (UpdateResult.ValueChanged | UpdateResult.InheritedValueOverridden))
                        == UpdateResult.ValueChanged;
                    // return false if either the value didn't change or
                    // it changed because the inherited value was overridden by coercion or animation.
                }
                else
                {
                    return false;
                }
            }

            // Do not continue walk down subtree if the walk was forced to stop
            // (due to separated trees)
            return (inheritanceBehavior == InheritanceBehavior.Default || isForceInheritedProperty);
        }