TreeWalkHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / TreeWalkHelper.cs / 1305600 / TreeWalkHelper.cs

                            /****************************************************************************\ 
*
* File: TreeWalkHelper.cs
*
*  Tree walk helper methods. 
*
* Copyright (C) 2005 by Microsoft Corporation.  All rights reserved. 
* 
\***************************************************************************/
 
using MS.Internal;
using MS.Utility;
using System;
using System.Diagnostics; 
using System.Security;
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Documents;
using System.Windows.Media; 

namespace System.Windows
{
    #region TreeWalkHelper 

    ///  
    ///     This is a static helper class that has methods 
    ///     that use the DescendentsWalker to do tree walks.
    ///  
    internal static class TreeWalkHelper
    {
        #region TreeChange
 
        /// 
        ///     Invalidate inheritable properties and resource 
        ///     references during a tree change operation. 
        /// 
        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 walker = new PrePostDescendentsWalker(
                        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 
                OnPostAncestorChanged(d, parentInfo);
            } 
        }

        /// 
        ///     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.
        ///  
        private static bool OnAncestorChanged(
            DependencyObject d,
            TreeChangeInfo   info)
        { 
            // Invalidate properties on current instance
            FrameworkObject fo = new FrameworkObject(d, true); 
 
            OnAncestorChanged(fo.FE, fo.FCE, info);
 
            // Continue walk down subtree
            return true;
        }
 
        /// 
        ///     OnAncestorChanged variant when we know what type (FE/FCE) the 
        ///     tree node is. 
        /// 
        ///  
        ///     Critical: This code calls into PresentationSource.OnAncestorChanged which is link demand protected
        ///     it does so only for content elements and not for FEs. But if called externally and configured
        ///     inappropriately it can be used to change the tree
        ///     TreatAsSafe: This does not let you get at the presentationsource which is what we do not want to expose 
        /// 
        [SecurityCritical,SecurityTreatAsSafe] 
        private static void OnAncestorChanged( 
            FrameworkElement        fe,
            FrameworkContentElement fce, 
            TreeChangeInfo          info)
        {
            if (fe!= null)
            { 
                fe.OnAncestorChangedInternal(info);
            } 
            else 
            {
                fce.OnAncestorChangedInternal(info); 
            }
        }

        ///  
        ///     This is called when the PrePostDescendentsWalker is done with the given
        ///     node and its subtree. 
        ///  
        private static bool OnPostAncestorChanged(
            DependencyObject d, 
            TreeChangeInfo   info)
        {
            // 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;
        }

        ///  
        ///     Invalidate all the properties in the given
        ///     collection of inheritable properties 
        ///  
        /// 
        ///     This method is called during an [FE/FCE].OnAncestorChange 
        /// 
        internal static FrugalObjectList InvalidateTreeDependentProperties(
            TreeChangeInfo                       info,
            FrameworkElement                     fe, 
            FrameworkContentElement              fce,
            Style                                selfStyle, 
            Style                                selfThemeStyle, 
            ref ChildRecord                      childRecord,
            bool                                 isChildRecordValid, 
            bool                                 hasStyleChanged,
            bool                                 isSelfInheritanceParent)
        {
            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 parentInheritableProperties = info.InheritablePropertiesStack.Peek(); 

            // Loop through all cached inheritable
            // to see if they should be invalidated.
            int inheritablePropertiesCount = parentInheritableProperties  != null ? parentInheritableProperties.Count : 0; 

            FrugalObjectList currentInheritableProperties = null; 
            if (HasChildren(fe, fce)) 
            {
                currentInheritableProperties = new FrugalObjectList(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);

                    // 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;
        } 

        ///  
        ///     Invalidate this property if 
        ///     - It is not locally set and
        ///     - It is not acquired from a style/template 
        /// 
        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;
        }
 
        #endregion TreeChange
 
        #region ResourcesChange 

        ///  
        ///     Invalidates all the properties on the nodes in the given sub-tree
        ///     that are referring to the resource[s] that are changing.
        /// 
        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."); 

            // 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 walker = new DescendentsWalker(
                    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);
            }
        } 

        ///  
        ///     Callback on visiting each node in the descendency 
        ///     during a resources change.
        ///  
        private static bool OnResourcesChangedCallback(
            DependencyObject    d,
            ResourcesChangeInfo info)
        { 
            OnResourcesChanged(d, info, true);
 
            // Continue walk down subtree 
            return true;
        } 


        /// 
        ///     Process a resource change for the given DependencyObject. 
        ///     Return true if the DO has resource references.
        ///  
        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 (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)); 
                }
            }
        }
 
        /// 
        ///     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.
        ///  
        /// 
        ///     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 
        /// 
        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); 
                } 
            }
        } 

        /// 
        ///     Invalidates all properties that reference a resource and are set via a style/template.
        ///  
        /// 
        ///     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
        ///  
        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();
                } 
                else 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();
                }
                else 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

        /// 
        ///  
        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 walker = new DescendentsWalker( 
                    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.
                OnInheritablePropertyChanged(fo.DO, info); 
            }
        } 
 
        /// 
        ///     Callback on visiting each node in the descendency 
        ///     during an inheritable property change
        /// 
        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);
        } 

        // 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);
            }
        } 

        ///  
        ///     Determine if the current DependencyObject is a candidate for 
        ///     producing inheritable values
        ///  
        /// 
        ///     This is called by both InvalidateTree and GetValueCore
        /// 
        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;
        } 
 
        /// 
        ///     FrameworkElement variant of IsInheritanceNode 
        /// 
        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; 
        }

        /// 
        ///     FrameworkContentElement variant of IsInheritanceNode 
        /// 
        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; 
        }
 
        ///  
        ///     Says if the given value has SkipNow behavior
        ///  
        internal static bool SkipNow(InheritanceBehavior inheritanceBehavior)
        {
            if (inheritanceBehavior == InheritanceBehavior.SkipToAppNow ||
                inheritanceBehavior == InheritanceBehavior.SkipToThemeNow || 
                inheritanceBehavior == InheritanceBehavior.SkipAllNow)
            { 
                return true; 
            }
 
            return false;
        }

        ///  
        ///     Says if the given value has SkipNext behavior
        ///  
        internal static bool SkipNext(InheritanceBehavior inheritanceBehavior) 
        {
            if (inheritanceBehavior == InheritanceBehavior.SkipToAppNext || 
                inheritanceBehavior == InheritanceBehavior.SkipToThemeNext ||
                inheritanceBehavior == InheritanceBehavior.SkipAllNext)
            {
                return true; 
            }
 
            return false; 
        }
 
        #endregion InheritablePropertyChange

        #region PrivateMethods
 
        /// 
        ///     Says if the current FE or FCE has visual or logical children 
        ///  
        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) 
                      );
        } 

        /// 
        ///     Says if the given property is a force inherited property
        ///  
        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 TreeChangeDelegate 
            = new VisitedCallback(OnAncestorChanged);
 
        private static VisitedCallback TreeChangePostDelegate 
            = new VisitedCallback(OnPostAncestorChanged);
 
        private static VisitedCallback ResourcesChangeDelegate
            = new VisitedCallback(OnResourcesChangedCallback);

        private static VisitedCallback InheritablePropertyChangeDelegate 
            = new VisitedCallback(OnInheritablePropertyChanged);
 
        #endregion StaticData 
    }
 
    #endregion TreeWalkHelper
}

 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK