Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Framework / System / Windows / TreeWalkHelper.cs / 2 / 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. PrePostDescendentsWalkerwalker = 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 FrugalObjectListInvalidateTreeDependentProperties( 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 */, operationType) & UpdateResult.ValueChanged) != 0; } 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 */, operationType) & UpdateResult.ValueChanged) != 0; } } 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 // 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, ResourcesChangeDelegate)) { DescendentsWalkerwalker = new DescendentsWalker ( TreeWalkPriority.LogicalTree, ResourcesChangeDelegate, info); fcdata.AddWalker(ResourcesChangeDelegate, walker); try { walker.StartWalk(d); } finally { fcdata.RemoveWalker(ResourcesChangeDelegate, walker); } } } 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) { 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; DescendentsWalkerwalker = 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 */, OperationType.Inherit) & UpdateResult.ValueChanged) != 0; } 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 */, OperationType.Inherit) & UpdateResult.ValueChanged) != 0; } 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 VisitedCallbackTreeChangeDelegate = 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- GrammarBuilderRuleRef.cs
- WebPartZone.cs
- ErrorFormatterPage.cs
- AuthenticationSection.cs
- Literal.cs
- ListDependantCardsRequest.cs
- _DisconnectOverlappedAsyncResult.cs
- RelationshipConstraintValidator.cs
- KeyedHashAlgorithm.cs
- XmlNodeWriter.cs
- HybridWebProxyFinder.cs
- BulletedListEventArgs.cs
- DesignerRegionMouseEventArgs.cs
- CodeIterationStatement.cs
- PathFigureCollection.cs
- QilValidationVisitor.cs
- QueryStringParameter.cs
- PriorityQueue.cs
- VectorAnimationUsingKeyFrames.cs
- ThemeInfoAttribute.cs
- SchemaImporterExtensionElement.cs
- ComponentResourceManager.cs
- TextViewDesigner.cs
- TypeConverter.cs
- ControlPropertyNameConverter.cs
- DbFunctionCommandTree.cs
- Hashtable.cs
- Manipulation.cs
- KoreanLunisolarCalendar.cs
- EndPoint.cs
- TransferRequestHandler.cs
- RawStylusInput.cs
- PartitionedStream.cs
- JumpList.cs
- SafeThreadHandle.cs
- DebugController.cs
- ClientSideQueueItem.cs
- StyleSheet.cs
- MTConfigUtil.cs
- ServiceProviders.cs
- SplineKeyFrames.cs
- CapacityStreamGeometryContext.cs
- AccessibleObject.cs
- IsolationInterop.cs
- ExpressionBuilderCollection.cs
- PropertyReferenceSerializer.cs
- DataObjectEventArgs.cs
- PageCatalogPart.cs
- DependencyPropertyValueSerializer.cs
- SystemUnicastIPAddressInformation.cs
- ResourceDictionary.cs
- XmlILConstructAnalyzer.cs
- SecurityCapabilities.cs
- FindCriteriaElement.cs
- XmlSchemaAnyAttribute.cs
- BindingGroup.cs
- ZipIOEndOfCentralDirectoryBlock.cs
- GlobalizationAssembly.cs
- FormViewDeleteEventArgs.cs
- BlurEffect.cs
- InheritanceAttribute.cs
- ReferenceConverter.cs
- UnsafeMethods.cs
- XmlSchemaSimpleTypeList.cs
- TriggerCollection.cs
- PermissionAttributes.cs
- FusionWrap.cs
- DropAnimation.xaml.cs
- CalendarKeyboardHelper.cs
- SortedDictionary.cs
- KnownTypesHelper.cs
- RequestContext.cs
- ContainerControlDesigner.cs
- ContractHandle.cs
- DynamicVirtualDiscoSearcher.cs
- OciLobLocator.cs
- DashStyle.cs
- AmbientLight.cs
- dataSvcMapFileLoader.cs
- PersistenceProviderElement.cs
- MultiBindingExpression.cs
- TextBox.cs
- ProviderSettingsCollection.cs
- UpdatePanel.cs
- DefaultObjectSerializer.cs
- DataGridTextBox.cs
- FormViewInsertedEventArgs.cs
- BoundColumn.cs
- SpinWait.cs
- SecurityNegotiationException.cs
- ImageClickEventArgs.cs
- TraceRecords.cs
- X509Certificate2.cs
- ListViewItem.cs
- MemberInfoSerializationHolder.cs
- COM2PropertyBuilderUITypeEditor.cs
- WorkflowQueue.cs
- AnonymousIdentificationModule.cs
- Metafile.cs
- Clipboard.cs