File: System\Windows\TreeWalkHelper.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
/***************************************************************************\
*
*
*  Tree walk helper methods.
*
*
\***************************************************************************/
using MS.Internal;
using MS.Utility;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
 
namespace System.Windows
{
    #region TreeWalkHelper
 
    /// <summary>
    ///     This is a static helper class that has methods
    ///     that use the DescendentsWalker to do tree walks.
    /// </summary>
    internal static class TreeWalkHelper
    {
        #region TreeChange
 
        /// <summary>
        ///     Invalidate inheritable properties and resource
        ///     references during a tree change operation.
        /// </summary>
        internal static void InvalidateOnTreeChange(
            FrameworkElement        fe,
            FrameworkContentElement fce,
            DependencyObject        parent,
            bool                    isAddOperation)
        {
            Debug.Assert(fe != null || fce != null, "Node with the tree change notification must be an FE or an FCE.");
            Debug.Assert(parent != null, "Must have a parent that the current node is connected to or disconnected from.");
 
            // If the tree change is for a non-FE/FCE parent then we need to find
            // the nearest FE/FCE parent inorder to propagate inheritance correctly.
            FrameworkObject parentFO = new FrameworkObject(parent);
            if (!parentFO.IsValid)
            {
                parent = parentFO.FrameworkParent.DO;
            }
 
            // We're interested in changes to the Template property that occur during
            // the walk - if the template has changed we don't need to invalidate
            // template-driven properties a second time.  The HasTemplateChanged property
            // is cleared on the first visit to each node, so that it means "template
            // changed during the walk".  But one relevant node isn't visited during
            // the walk - the templated parent of the initial node.  So we handle that now.
            FrameworkObject fo = new FrameworkObject(fe, fce);
 
            // Synchronize the ShouldLookupImplicitStyles flag with respect to the parent here
            // because for the root node of a tree change UpdateStyleProperty happens right here
            // in this method. And we need to have synchrnozed the ShouldLookupImplicitStyles
            // before we re-query the Style property.
 
            if (isAddOperation)
            {
                fo.SetShouldLookupImplicitStyles();
            }
 
            fo.Reset(fo.TemplatedParent);
            fo.HasTemplateChanged = false;
 
            DependencyObject d = (fe != null) ? (DependencyObject)fe : (DependencyObject)fce;
 
            // during a tree walk to invalidate inherited properties, we typically
            // call UpdateStyle from FE/FCE.InvalidateTreeDependentProperties.  But
            // for the root element of the tree change, we need to record old values
            // for inherited properties before we've updated the inheritance parent;
            // so do the updatestyle here before we record old values so that we
            // capture any updates provided by styles.
            if (fe != null)
            {
                if (fe.IsInitialized && !fe.HasLocalStyle)
                {
                    // Clear the HasStyleChanged flag
                    fe.HasStyleChanged = false;
                    fe.HasStyleInvalidated = false;
                    fe.HasTemplateChanged = false;
 
                    fe.AncestorChangeInProgress = true;
                    fe.UpdateStyleProperty();
                    fe.AncestorChangeInProgress = false;
                }
            }
            else
            {
                if (!fce.HasLocalStyle)
                {
                    // Clear the HasStyleChanged flag
                    fce.HasStyleChanged = false;
                    fce.HasStyleInvalidated = false;
 
                    fce.AncestorChangeInProgress = true;
                    fce.UpdateStyleProperty();
                    fce.AncestorChangeInProgress = false;
                }
            }
 
            if (HasChildren(fe, fce))
            {
                // Spin up a DescendentsWalker only when
                // the current node has children to walk
 
                // If there is another tree walk that has already visited the
                // current node then we do not need to re-walk its sub-tree.
                FrameworkContextData fcdata = FrameworkContextData.From(d.Dispatcher);
                if (!fcdata.WasNodeVisited(d, TreeChangeDelegate))
                {
                    // The TreeChangeInfo object is used here to track
                    // information that we have because we're doing a tree walk.
                    TreeChangeInfo parentInfo = new TreeChangeInfo(d, parent, isAddOperation);
 
                    // PrePostDescendentsWalker is used instead of the standard
                    // DescendentsWalker because we need a "post" callback to know when
                    // to pop the parent's InheritableProperties cache from the stack.
                    PrePostDescendentsWalker<TreeChangeInfo> walker = new PrePostDescendentsWalker<TreeChangeInfo>(
                        TreeWalkPriority.LogicalTree, TreeChangeDelegate, TreeChangePostDelegate, parentInfo);
 
                    fcdata.AddWalker(TreeChangeDelegate, walker);
 
                    try
                    {
                        walker.StartWalk(d);
                    }
                    finally
                    {
                        fcdata.RemoveWalker(TreeChangeDelegate, walker);
                    }
                }
            }
            else
            {
                // Degenerate case when the current node is a leaf node and has no children.
 
                TreeChangeInfo parentInfo = new TreeChangeInfo(d, parent, isAddOperation);
 
                // Degenerate case of OnAncestorChanged for a single node
                OnAncestorChanged(fe, fce, parentInfo);
 
                // Degenerate case of OnPostAncestorChanged for a single node
                bool visitedViaVisualTree = false;
                OnPostAncestorChanged(d, parentInfo, visitedViaVisualTree);
            }
        }
 
        /// <summary>
        ///     Callback on visiting each node in the descendency during a tree change
        ///     Note that this is only used in an entire sub-tree undergoes a change.
        ///     If the tree change is happening on a single node with no children, this
        ///     invalidation happens inside InvalidateOnTreeChange and this method doesn't
        ///     get involved.
        /// </summary>
        private static bool OnAncestorChanged(
            DependencyObject d,
            TreeChangeInfo   info,
            bool             visitedViaVisualTree)
        {
            // Invalidate properties on current instance
            FrameworkObject fo = new FrameworkObject(d, true);
 
            OnAncestorChanged(fo.FE, fo.FCE, info);
 
            // Continue walk down subtree
            return true;
        }
 
        /// <summary>
        ///     OnAncestorChanged variant when we know what type (FE/FCE) the
        ///     tree node is.
        /// </summary>
        private static void OnAncestorChanged(
            FrameworkElement        fe,
            FrameworkContentElement fce,
            TreeChangeInfo          info)
        {
            if (fe!= null)
            {
                fe.OnAncestorChangedInternal(info);
            }
            else
            {
                fce.OnAncestorChangedInternal(info);
            }
        }
 
        /// <summary>
        ///     This is called when the PrePostDescendentsWalker is done with the given
        ///     node and its subtree.
        /// </summary>
        private static bool OnPostAncestorChanged(
            DependencyObject d,
            TreeChangeInfo   info,
            bool             visitedViaVisualTree)
        {
            // If the given node is the root of a collapsed subtree, we're
            // done with that subtree now and from this point forward, the given
            // node is not the "topmost collapsed parent node".
            // InvalidateTreeDependentProperties sets this reference when
            // appropriate, and OnPropertyChanged uses it to bypass
            // layout invalidation when in a collapsed subtree.
            if (info.TopmostCollapsedParentNode == d)
            {
                info.TopmostCollapsedParentNode = null;
            }
 
            // a return of true indicates that there was a cache set for this
            // node (meaning this node wasn't a leaf);
            // so pop the InheritableProperties cache for this node
            info.InheritablePropertiesStack.Pop();
 
            return true;
        }
 
        /// <summary>
        ///     Invalidate all the properties in the given
        ///     collection of inheritable properties
        /// </summary>
        /// <remarks>
        ///     This method is called during an [FE/FCE].OnAncestorChange
        /// </remarks>
        internal static FrugalObjectList<DependencyProperty> InvalidateTreeDependentProperties(
            TreeChangeInfo                       info,
            FrameworkElement                     fe,
            FrameworkContentElement              fce,
            Style                                selfStyle,
            Style                                selfThemeStyle,
            ref ChildRecord                      childRecord,
            bool                                 isChildRecordValid,
            bool                                 hasStyleChanged,
            bool                                 isSelfInheritanceParent,
            bool                                 wasSelfInheritanceParent)
        {
            Debug.Assert(fe != null || fce != null, "Must have non-null current node");
            DependencyObject d = fe != null ? (DependencyObject)fe : (DependencyObject)fce;
            FrameworkObject fo = new FrameworkObject(fe, fce);
 
            // Pull up the parent's InheritableProperties cache
            FrugalObjectList<DependencyProperty> parentInheritableProperties = info.InheritablePropertiesStack.Peek();
 
            // Loop through all cached inheritable
            // to see if they should be invalidated.
            int inheritablePropertiesCount = parentInheritableProperties  != null ? parentInheritableProperties.Count : 0;
 
            FrugalObjectList<DependencyProperty> currentInheritableProperties = null;
            if (HasChildren(fe, fce))
            {
                currentInheritableProperties = new FrugalObjectList<DependencyProperty>(inheritablePropertiesCount);
            }
 
            info.ResetInheritableValueIndexer();
 
            for (int i = 0; i < inheritablePropertiesCount; i++)
            {
                DependencyProperty inheritableProperty = parentInheritableProperties[i];
 
                Debug.Assert(inheritableProperty.IsPotentiallyInherited, "if we got here, it means that this property is inheritable by someone");
 
                PropertyMetadata metadata = inheritableProperty.GetMetadata(d);
 
                // Invalidate only properties that are marked as inheritable.
                // These are the ones that will be affected by an ancestor changes.
                if (metadata.IsInherited)
                {
                    FrameworkPropertyMetadata fMetadata = (FrameworkPropertyMetadata)metadata;
 
                    bool changed = InvalidateTreeDependentProperty(info, d, ref fo, inheritableProperty, fMetadata,
                        selfStyle, selfThemeStyle, ref childRecord, isChildRecordValid, hasStyleChanged, isSelfInheritanceParent, wasSelfInheritanceParent);
 
                    // If a change is detected then add the inheritable property to
                    // the current list so that it can be used to invalidate further children
                    if (changed && currentInheritableProperties != null)
                    {
                        Debug.Assert(!currentInheritableProperties.Contains(inheritableProperty), "InheritableProperties list should not have duplicates");
 
                        // Children do not need to inherit properties across a tree boundary
                        // unless the property is set to override this behavior.
 
                        if (!SkipNow(fo.InheritanceBehavior) || fMetadata.OverridesInheritanceBehavior)
                        {
                            currentInheritableProperties.Add(inheritableProperty);
                        }
                    }
                }
            }
 
            return currentInheritableProperties;
        }
 
        /// <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,
            bool                        wasSelfInheritanceParent)
        {
            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");
 
            // IsSelfInheritanceParent can only change from false to true
            Debug.Assert(!wasSelfInheritanceParent || isSelfInheritanceParent, "IsSelfInheritanceParent changed from true to false");
 
            // 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 (wasSelfInheritanceParent)
                    {
                        oldEntry = d.GetValueEntry(
                                d.LookupEntry(dp.GlobalIndex),
                                dp,
                                fMetadata,
                                RequestFlags.DeferredReferences);
                    }
                    else if (isSelfInheritanceParent)
                    {
                        // IsSelfInheritanceParent can change from false to true during
                        // a visual tree change if the change induces a style change
                        // (from a DynamicResource or implicit style that now resolves)
                        // where the new style sets an inheritable property.  In this
                        // case, we should not invalidate the current property if it
                        // was set by the new style, but allow other
                        // properties to propagate as if the style change and
                        // IsSelfInheritanceParent change hadn't happened 
                        EffectiveValueEntry currentEntry = d.GetValueEntry(
                                d.LookupEntry(dp.GlobalIndex),
                                dp,
                                fMetadata,
                                RequestFlags.DeferredReferences);
                        if (currentEntry.BaseValueSourceInternal <= BaseValueSourceInternal.Inherited)
                        {
                            oldEntry = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
                            oldEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
                        }
                        else
                        {
                            oldEntry = currentEntry;
                        }
                    }
                    else
                    {
                        oldEntry = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved);
                        oldEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited;
                    }
                }
                else if (info.IsAddOperation &&
                    (isForceInheritedProperty || oldEntry.BaseValueSourceInternal <= BaseValueSourceInternal.Inherited))
                {
                    // before calling UpdateEffectiveValue on the root of the changed subtree,
                    // see if the property now has a higher-precedence value because
                    // a resource reference now resolves.  If so, don't invalidate 
                    EffectiveValueEntry currentEntry = d.GetValueEntry(
                        d.LookupEntry(dp.GlobalIndex),
                        dp,
                        fMetadata,
                        RequestFlags.DeferredReferences);
                    if (currentEntry.BaseValueSourceInternal > BaseValueSourceInternal.Inherited)
                    {
                        oldEntry = currentEntry;
                    }
                }
 
                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;
        }
 
        #endregion TreeChange
 
        #region ResourcesChange
 
        /// <summary>
        ///     Invalidates all the properties on the nodes in the given sub-tree
        ///     that are referring to the resource[s] that are changing.
        /// </summary>
        internal static void InvalidateOnResourcesChange(
            FrameworkElement        fe,
            FrameworkContentElement fce,
            ResourcesChangeInfo     info)
        {
            Debug.Assert(fe != null || fce != null, "Node with the resources change notification must be an FE or an FCE.");
 
            // Here we are syncing the window's Theme mode if resource dictionary changes.
            // The IgnoreWindowResourcesChange is a flag set to make sure the ThemeMode change does not cause an infinite loop of resource changes.
            if(fe is Window currentWindow)
            {
                currentWindow.AreResourcesInitialized = true;
                if(!ThemeManager.IgnoreWindowResourcesChange)
                {
                    ThemeManager.SyncWindowThemeMode(currentWindow);
                }
            }
 
            // We're interested in changes to the Template property that occur during
            // the walk - if the template has changed we don't need to invalidate
            // template-driven properties a second time.  The HasTemplateChanged property
            // is cleared on the first visit to each node, so that it means "template
            // changed during the walk".  But one relevant node isn't visited during
            // the walk - the templated parent of the initial node.  So we handle that now.
            FrameworkObject fo = new FrameworkObject(fe, fce);
 
            fo.Reset(fo.TemplatedParent);
            fo.HasTemplateChanged = false;
 
            DependencyObject d = (fe != null) ? (DependencyObject)fe : (DependencyObject)fce;
 
            if (HasChildren(fe, fce))
            {
                // Spin up a DescendentsWalker only when
                // the current node has children to walk
 
                DescendentsWalker<ResourcesChangeInfo> walker = new DescendentsWalker<ResourcesChangeInfo>(
                    TreeWalkPriority.LogicalTree, ResourcesChangeDelegate, info);
 
                walker.StartWalk(d);
            }
            else
            {
                // Degenerate case when the current node is a leaf node and has no children.
 
                OnResourcesChanged(d, info, true);
            }
        }
 
        /// <summary>
        ///     Callback on visiting each node in the descendency
        ///     during a resources change.
        /// </summary>
        private static bool OnResourcesChangedCallback(
            DependencyObject    d,
            ResourcesChangeInfo info,
            bool                visitedViaVisualTree)
        {
            OnResourcesChanged(d, info, true);
 
            // Continue walk down subtree
            return true;
        }
 
 
        /// <summary>
        ///     Process a resource change for the given DependencyObject.
        ///     Return true if the DO has resource references.
        /// </summary>
        internal static void OnResourcesChanged(
            DependencyObject    d,
            ResourcesChangeInfo info,
            bool raiseResourceChangedEvent)
        {
            Debug.Assert(d != null, "Must have non-null current node");
 
            bool containsTypeOfKey = info.Contains(d.DependencyObjectType.SystemType, true /*isImplicitStyleKey*/);
            bool isSystemResourcesChange = info.IsThemeChange;
            bool isStyleResourcesChange = info.IsStyleResourcesChange;
            bool isTemplateResourcesChange = info.IsTemplateResourcesChange;
            bool isContainer = (info.Container == d);
 
            FrameworkObject fo = new FrameworkObject(d);
 
            // If a resource dictionary changed above this node then we need to
            // synchronize the ShouldLookupImplicitStyles flag with respect to
            // our parent here.
 
            if (info.IsResourceAddOperation || info.IsCatastrophicDictionaryChange)
            {
                fo.SetShouldLookupImplicitStyles();
            }
 
            // Invalidate implicit and explicit resource
            // references on current instance
            if (fo.IsFE)
            {
                // If this is a FrameworkElement
                FrameworkElement fe = fo.FE;
                fe.HasStyleChanged = false; // detect style changes that arise from work done here
                fe.HasStyleInvalidated = false;
                fe.HasTemplateChanged = false; // detect template changes that arise from work done here
 
                // if the change affects implicit data templates, notify ContentPresenters
                if (info.IsImplicitDataTemplateChange)
                {
                    ContentPresenter contentPresenter = fe as ContentPresenter;
                    if (contentPresenter != null)
                    {
                        contentPresenter.ReevaluateTemplate();
                    }
                }
 
                if (fe.HasResourceReference)
                {
                    // Invalidate explicit ResourceReference properties on the current instance.
                    // If the Style property comes from an implicit resource reference that
                    // will be invalidated too.
                    InvalidateResourceReferences(fe, info);
 
                    // There is no need to invalidate the resources references on the
                    // container object if this call is a result of a style/template
                    // change. This is because the style/template change would have
                    // already invalidated all the container dependents and all the
                    // resources references on the container would have been a part of it.
                    if ((!isStyleResourcesChange && !isTemplateResourcesChange ) || !isContainer)
                    {
                        InvalidateStyleAndReferences(d, info, containsTypeOfKey);
                    }
                }
                else if (containsTypeOfKey &&
                        (fe.HasImplicitStyleFromResources || fe.Style == FrameworkElement.StyleProperty.GetMetadata(fe.DependencyObjectType).DefaultValue))
                {
                    // If The Style property on the given instance has been
                    // fetched by an implicit resource lookup then
                    // it needs to be invalidated. Also we need to do this
                    // invalidation only if the dictionary/resources that is
                    // changing matches the implicit key used for the resource lookup.
 
                    // The StyleProperty does not need to be invalidated if this
                    // call is the result of a style change
                    if (!isStyleResourcesChange || !isContainer)
                    {
                        fe.UpdateStyleProperty();
                    }
                }
 
                // If there has been a Theme change then
                // invalidate the ThemeStyleProperty
                if (isSystemResourcesChange)
                {
                    fe.UpdateThemeStyleProperty();
                }
 
                // Raise the ResourcesChanged Event so that ResourceReferenceExpressions
                // on non-[FE/FCE] (example Freezables) listening for this can then update
                // their values
                if (raiseResourceChangedEvent && fe.PotentiallyHasMentees)
                {
                    fe.RaiseClrEvent(FrameworkElement.ResourcesChangedKey, new ResourcesChangedEventArgs(info));
                }
            }
            else
            {
                // If this is a FrameworkContentElement
                FrameworkContentElement fce = fo.FCE;
                fce.HasStyleChanged = false; // detect style changes that arise from work done here
                fce.HasStyleInvalidated = false;
 
                if (fce.HasResourceReference)
                {
                    // Invalidate explicit ResourceReference properties on the current instance.
                    // If the Style property comes from an implicit resource reference that
                    // will be invalidated too.
                    InvalidateResourceReferences(fce, info);
 
                    // There is no need to invalidate the resources references on the
                    // container object if this call is a result of a style/template
                    // change. This is because the style/template change would have
                    // already invalidated all the container dependents and all the
                    // resources references on the container would have been a part of it.
                    if ((!isStyleResourcesChange && !isTemplateResourcesChange ) || !isContainer)
                    {
                        InvalidateStyleAndReferences(d, info, containsTypeOfKey);
                    }
                }
                else if (containsTypeOfKey &&
                        (fce.HasImplicitStyleFromResources || fce.Style == FrameworkContentElement.StyleProperty.GetMetadata(fce.DependencyObjectType).DefaultValue))
                {
                    // If The Style property on the given instance has been
                    // fetched by an implicit resource lookup then
                    // it needs to be invalidated. Also we need to do this
                    // invalidation only if the dictionary/resources that is
                    // changing matches the implicit key used for the resource lookup.
 
                    // The StyleProperty does not need to be invalidated if this
                    // call is the result of a style change
                    if (!isStyleResourcesChange || !isContainer)
                    {
                        fce.UpdateStyleProperty();
                    }
                }
 
                // If there has been a Theme change then
                // invalidate the ThemeStyleProperty
                if (isSystemResourcesChange)
                {
                    fce.UpdateThemeStyleProperty();
                }
 
                // Raise the ResourcesChanged Event so that ResourceReferenceExpressions
                // on non-[FE/FCE] (example Freezables) listening for this can then update
                // their values
                if (raiseResourceChangedEvent && fce.PotentiallyHasMentees)
                {
                    fce.RaiseClrEvent(FrameworkElement.ResourcesChangedKey, new ResourcesChangedEventArgs(info));
                }
            }
        }
 
        /// <summary>
        ///     Invalidates all properties that reference a resource.
        ///     NOTE: The return value for this method indicates whether or not a ResourceReference
        ///     property was found on the given object. This is to take care of the special case when
        ///     programmatically changing a ResourceReference property value does not reflect on the
        ///     bit stored on FrameworkElement or FrameworkContentElement that indicates whether
        ///     the current instance has ResourceReference values set on it. This current operation
        ///     is a point of synchronization for this flag.
        /// </summary>
        /// <remarks>
        ///     This methods is called when one of the following operations occurred.
        ///     1) A tree change
        ///     2) A resource dictionary change
        ///     3) A modification to a single entry in a dictionary
        /// </remarks>
        private static void InvalidateResourceReferences(
            DependencyObject    d,
            ResourcesChangeInfo info)
        {
            Debug.Assert(d != null, "Must have non-null current node");
 
            // Find properties that have resource reference value
            LocalValueEnumerator localValues = d.GetLocalValueEnumerator();
            int localValuesCount = localValues.Count;
 
            if (localValuesCount > 0)
            {
                // Resource reference invalidation involves two passes - first to
                // pick out what we need to invalidate, and the second to do the
                // actual invalidation.  This is needed because LocalValueEnumerator
                // will halt if any local values have changed, which can happen
                // depending on what people are doing in their OnPropertyChanged
                // callback.
 
                // The following array is used to track the ResourceReferenceExpressions that we find
                ResourceReferenceExpression[] resources = new ResourceReferenceExpression[localValuesCount];
                int invalidationCount = 0;
 
                // Pass #1 - find what needs invalidation
                while (localValues.MoveNext())
                {
                    // Is this a resource reference?
                    ResourceReferenceExpression resource = localValues.Current.Value as ResourceReferenceExpression;
                    if (resource != null)
                    {
                        // Record this property if it is referring
                        // to a resource that is being changed
                        if (info.Contains(resource.ResourceKey, false /*isImplicitStyleKey*/))
                        {
                            resources[invalidationCount]  = resource;
                            invalidationCount++;
                        }
                    }
                }
 
                ResourcesChangedEventArgs args = new ResourcesChangedEventArgs(info);
 
                // Pass #2 - actually make the invalidation calls, now that we're
                // outside the LocalValueEnumerator.
                for (int i = 0; i < invalidationCount; i++)
                {
                    // Let the resource reference throw away its cache
                    // and invalidate the property in which it's held
                    // re-evaluate expression
                    resources[i].InvalidateExpressionValue(d, args);
                }
            }
        }
 
        /// <summary>
        ///     Invalidates all properties that reference a resource and are set via a style/template.
        /// </summary>
        /// <remarks>
        ///     This methods is called when one of the following operations occurred.
        ///     1) A resource dictionary change
        ///     2) A modification to a single entry in a dictionary
        /// </remarks>
        private static void InvalidateStyleAndReferences(
            DependencyObject    d,
            ResourcesChangeInfo info,
            bool                containsTypeOfKey)
        {
            Debug.Assert(d != null, "Must have non-null current node");
 
            FrameworkObject fo = new FrameworkObject(d);
 
            if (fo.IsFE)
            {
                FrameworkElement fe = fo.FE;
 
                if (containsTypeOfKey &&
                    !info.IsThemeChange &&
                    (fe.HasImplicitStyleFromResources || fe.Style == FrameworkElement.StyleProperty.GetMetadata(fe.DependencyObjectType).DefaultValue))
                {
                    // If The Style property on the given instance has been
                    // fetched by an implicit resource lookup then
                    // it needs to be invalidated. Also we need to do this
                    // invalidation only if the dictionary/resources that is
                    // changing matches the implicit key used for the resource lookup.
                    // If we invalidate the style then we do not need to
                    // InvalidateResourceDependents because applying an
                    // all new style will have the same effect
                    fe.UpdateStyleProperty();
                }
 
                if (fe.Style != null && fe.Style.HasResourceReferences)
                {
                    // Check for resource references contained within associated Style.
                    // If found, invalidate all properties that are being driven by a resource.
                    // If the style has changed recently, that change would have already
                    // invalidated these properties.
                    if (!fe.HasStyleChanged)
                    {
                        StyleHelper.InvalidateResourceDependents(d, info, ref fe.Style.ResourceDependents,
                            false /* invalidateVisualTreeToo */);
                    }
                }
 
                if (fe.TemplateInternal != null && fe.TemplateInternal.HasContainerResourceReferences)
                {
                    // Check for resource references contained within associated Template.
                    // If found, invalidate all properties that are being driven by a resource
                    StyleHelper.InvalidateResourceDependents(d, info, ref fe.TemplateInternal.ResourceDependents,
                        false /* invalidateVisualTreeToo */);
                }
 
                if (fe.TemplateChildIndex > 0)
                {
                    // Check for resource references contained within parent's Template.
                    // If found, invalidate all properties that are being driven by a resource
                    FrameworkElement templatedParent = (FrameworkElement)fe.TemplatedParent;
                    FrameworkTemplate parentTemplate = templatedParent.TemplateInternal;
 
                    if (!templatedParent.HasTemplateChanged && parentTemplate.HasChildResourceReferences)
                    {
                        StyleHelper.InvalidateResourceDependentsForChild(
                                            templatedParent,
                                            fe,
                                            fe.TemplateChildIndex,
                                            info,
                                            parentTemplate);
                    }
                }
 
 
                if (!info.IsThemeChange)
                {
                    // Invalidate ResourceReferences on ThemeStyle only if this insn't a Theme change.
                    // It it is then ThemeStyle would already have been invalidated and hence there isn't
                    // a need to duplicate it here.
                    Style themeStyle = fe.ThemeStyle;
                    if (themeStyle != null && themeStyle.HasResourceReferences)
                    {
                        if (themeStyle != fe.Style)
                        {
                            StyleHelper.InvalidateResourceDependents(d, info, ref themeStyle.ResourceDependents,
                                false /* invalidateVisualTreeToo */);
                        }
                    }
                }
            }
            else if (fo.IsFCE)
            {
                FrameworkContentElement fce = fo.FCE;
 
                if (containsTypeOfKey &&
                    !info.IsThemeChange &&
                    (fce.HasImplicitStyleFromResources || fce.Style == FrameworkContentElement.StyleProperty.GetMetadata(fce.DependencyObjectType).DefaultValue))
                {
                    // If The Style property on the given instance has been
                    // fetched by an implicit resource lookup then
                    // it needs to be invalidated. Also we need to do this
                    // invalidation only if the dictionary/resources that is
                    // changing matches the implicit key used for the resource lookup.
                    // If we invalidate the style then we do not need to
                    // InvalidateResourceDependents because applying an
                    // all new style will have the same effect
                    fce.UpdateStyleProperty();
                }
 
                if (fce.Style != null && fce.Style.HasResourceReferences)
                {
                    // Check for resource references contained within associated Style.
                    // If found, invalidate all properties that are being driven by a resource
                    // If the style has changed recently, that change would have already
                    // invalidated these properties.
                    if (!fce.HasStyleChanged)
                    {
                        StyleHelper.InvalidateResourceDependents(d, info, ref fce.Style.ResourceDependents, !
                            false /*invalidateVisualTreeToo */);
                    }
                }
 
 
                if (fce.TemplateChildIndex > 0)
                {
                    // Check for resource references contained within parent's Template.
                    // If found, invalidate all properties that are being driven by a resource
                    FrameworkElement templatedParent = (FrameworkElement)fce.TemplatedParent;
                    FrameworkTemplate parentTemplate = templatedParent.TemplateInternal;
 
                    if (!templatedParent.HasTemplateChanged && parentTemplate.HasChildResourceReferences)
                    {
                        StyleHelper.InvalidateResourceDependentsForChild(
                                            templatedParent,
                                            fce,
                                            fce.TemplateChildIndex,
                                            info,
                                            parentTemplate);
                    }
                }
 
                if (!info.IsThemeChange)
                {
                    // Invalidate ResourceReferences on ThemeStyle only if this insn't a Theme change.
                    // It it is then ThemeStyle would already have been invalidated and hence there isn't
                    // a need to duplicate it here.
                    Style themeStyle = fce.ThemeStyle;
                    if (themeStyle != null && themeStyle.HasResourceReferences)
                    {
                        if (themeStyle != fce.Style)
                        {
                            StyleHelper.InvalidateResourceDependents(d, info, ref themeStyle.ResourceDependents,
                                false /*invalidateVisualTreeToo */);
                        }
                    }
                }
            }
        }
 
        #endregion ResourcesChange
 
        #region InheritablePropertyChange
 
        /// <summary>
        /// </summary>
        internal static void InvalidateOnInheritablePropertyChange(
            FrameworkElement              fe,
            FrameworkContentElement       fce,
            InheritablePropertyChangeInfo info,
            bool                          skipStartNode)
        {
            DependencyProperty dp = info.Property;
            FrameworkObject fo = new FrameworkObject(fe, fce);
            Debug.Assert(fo.IsValid, "Node with the resources change notification must be an FE or an FCE.");
 
            if (HasChildren(fe, fce))
            {
                // Spin up a DescendentsWalker only when
                // the current node has children to walk
 
                DependencyObject d = fo.DO;
 
                DescendentsWalker<InheritablePropertyChangeInfo> walker = new DescendentsWalker<InheritablePropertyChangeInfo>(
                    TreeWalkPriority.LogicalTree, InheritablePropertyChangeDelegate, info);
 
                walker.StartWalk(d, skipStartNode);
            }
            else if (!skipStartNode)
            {
                // Degenerate case when the current node is a leaf node and has no children.
                // If the current node needs a notification, do so now.
                bool visitedViaVisualTree = false;
                OnInheritablePropertyChanged(fo.DO, info, visitedViaVisualTree);
            }
        }
 
        /// <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 && d is FrameworkElement)
                    {
                        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);
        }
 
        // raise the InheritedPropertyChanged event to mentees.  Called from FE/FCE
        // OnPropertyChanged
        internal static void OnInheritedPropertyChanged(DependencyObject d,
                                            ref InheritablePropertyChangeInfo info,
                                            InheritanceBehavior inheritanceBehavior)
        {
            if (inheritanceBehavior == InheritanceBehavior.Default || IsForceInheritedProperty(info.Property))
            {
                FrameworkObject fo = new FrameworkObject(d);
                fo.OnInheritedPropertyChanged(ref info);
            }
        }
 
        /// <summary>
        ///     Determine if the current DependencyObject is a candidate for
        ///     producing inheritable values
        /// </summary>
        /// <remarks>
        ///     This is called by both InvalidateTree and GetValueCore
        /// </remarks>
        internal static bool IsInheritanceNode(
            DependencyObject    d,
            DependencyProperty  dp,
        out InheritanceBehavior inheritanceBehavior)
        {
            // Assume can continue search
            inheritanceBehavior = InheritanceBehavior.Default;
 
            // Get Framework metadata (if exists)
            FrameworkPropertyMetadata metadata = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;
 
            // Check for correct type of metadata
            if (metadata != null)
            {
                FrameworkObject fo = new FrameworkObject(d);
 
                if (fo.IsValid)
                {
                    // If parent is a Framework type, then check if it is at a
                    // tree separation boundary. Stop inheritance at the boundary unless
                    // overridden by the medata.OverridesInheritanceBehavior flag.
 
                    // GetValue from Parent only if instance is not a TreeSeparator
                    // or fmetadata.OverridesInheritanceBehavior is set to override separated tree behavior
                    if (fo.InheritanceBehavior != InheritanceBehavior.Default && !metadata.OverridesInheritanceBehavior)
                    {
                        // Hit a tree boundary
                        inheritanceBehavior = fo.InheritanceBehavior;
                    }
                }
                else
                {
                    // If not a Framework type, then, this isn't an inheritance node.
                    // Only Framework types know how to inherit
 
                    return false;
                }
 
                // Check if metadata is marked as inheritable
                if (metadata.Inherits)
                {
                    return true;
                }
            }
 
            // Not a framework type with inheritable metadata
            return false;
        }
 
        /// <summary>
        ///     FrameworkElement variant of IsInheritanceNode
        /// </summary>
        internal static bool IsInheritanceNode(
            FrameworkElement        fe,
            DependencyProperty      dp,
            out InheritanceBehavior inheritanceBehavior)
        {
            // Assume can continue search
            inheritanceBehavior = InheritanceBehavior.Default;
 
            // Get Framework metadata (if exists)
            FrameworkPropertyMetadata metadata = dp.GetMetadata(fe.DependencyObjectType) as FrameworkPropertyMetadata;
 
            // Check for correct type of metadata
            if (metadata != null)
            {
                if (fe.InheritanceBehavior != InheritanceBehavior.Default && !metadata.OverridesInheritanceBehavior)
                {
                    // Hit a tree boundary
                    inheritanceBehavior = fe.InheritanceBehavior;
                }
 
                // Return true if metadata is marked as inheritable; false otherwise
                return metadata.Inherits;
            }
 
            // Not framework type metadata
            return false;
        }
 
        /// <summary>
        ///     FrameworkContentElement variant of IsInheritanceNode
        /// </summary>
        internal static bool IsInheritanceNode(
            FrameworkContentElement fce,
            DependencyProperty      dp,
            out InheritanceBehavior inheritanceBehavior)
        {
            // Assume can continue search
            inheritanceBehavior = InheritanceBehavior.Default;
 
            // Get Framework metadata (if exists)
            FrameworkPropertyMetadata metadata = dp.GetMetadata(fce.DependencyObjectType) as FrameworkPropertyMetadata;
 
            // Check for correct type of metadata
            if (metadata != null)
            {
                if (fce.InheritanceBehavior != InheritanceBehavior.Default && !metadata.OverridesInheritanceBehavior)
                {
                    // Hit a tree boundary
                    inheritanceBehavior = fce.InheritanceBehavior;
                }
 
                // Return true if metadata is marked as inheritable; false otherwise
                return metadata.Inherits;
            }
 
            // Not framework type metadata
            return false;
        }
 
        /// <summary>
        ///     Says if the given value has SkipNow behavior
        /// </summary>
        internal static bool SkipNow(InheritanceBehavior inheritanceBehavior)
        {
            if (inheritanceBehavior == InheritanceBehavior.SkipToAppNow ||
                inheritanceBehavior == InheritanceBehavior.SkipToThemeNow ||
                inheritanceBehavior == InheritanceBehavior.SkipAllNow)
            {
                return true;
            }
 
            return false;
        }
 
        /// <summary>
        ///     Says if the given value has SkipNext behavior
        /// </summary>
        internal static bool SkipNext(InheritanceBehavior inheritanceBehavior)
        {
            if (inheritanceBehavior == InheritanceBehavior.SkipToAppNext ||
                inheritanceBehavior == InheritanceBehavior.SkipToThemeNext ||
                inheritanceBehavior == InheritanceBehavior.SkipAllNext)
            {
                return true;
            }
 
            return false;
        }
 
        #endregion InheritablePropertyChange
 
        #region PrivateMethods
 
        /// <summary>
        ///     Says if the current FE or FCE has visual or logical children
        /// </summary>
        internal static bool HasChildren(FrameworkElement fe, FrameworkContentElement fce)
        {
            // See if we have logical or visual children, in which case this is a real tree invalidation.
            return ( (fe != null && (fe.HasLogicalChildren ||
                                               fe.HasVisualChildren ||
                                               (Popup.RegisteredPopupsField.GetValue(fe) != null)
                                              )
                         ) ||
                        (fce != null && fce.HasLogicalChildren)
                      );
        }
 
        /// <summary>
        ///     Says if the given property is a force inherited property
        /// </summary>
        private static bool IsForceInheritedProperty(DependencyProperty dp)
        {
            // NOTE: this is not really a force-inherited property, rather a property
            // that does not want to stop invalidations when a no-change state is
            // encountered.
            //
            // As of 2/5/2005, ForceInherited properties moved to Core, but
            // FlowDircectionProperty remains here to avoid a breaking change.
            return (dp == FrameworkElement.FlowDirectionProperty);
        }
 
        #endregion PrivateMethods
 
        #region StaticData
 
        // Delegates used for the DescendentsWalker TreeWalk.
 
        private static VisitedCallback<TreeChangeInfo> TreeChangeDelegate
            = new VisitedCallback<TreeChangeInfo>(OnAncestorChanged);
 
        private static VisitedCallback<TreeChangeInfo> TreeChangePostDelegate
            = new VisitedCallback<TreeChangeInfo>(OnPostAncestorChanged);
 
        private static VisitedCallback<ResourcesChangeInfo> ResourcesChangeDelegate
            = new VisitedCallback<ResourcesChangeInfo>(OnResourcesChangedCallback);
 
        private static VisitedCallback<InheritablePropertyChangeInfo> InheritablePropertyChangeDelegate
            = new VisitedCallback<InheritablePropertyChangeInfo>(OnInheritablePropertyChanged);
 
        #endregion StaticData
    }
 
    #endregion TreeWalkHelper
}