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.
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 */,
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))
{
DescendentsWalker walker = 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;
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 */,
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 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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Internal.cs
- ProviderConnectionPoint.cs
- ImageSourceConverter.cs
- CodeLabeledStatement.cs
- EditingCoordinator.cs
- InstancePersistenceException.cs
- ObjectToken.cs
- Facet.cs
- ContentDisposition.cs
- XPathParser.cs
- WorkflowValidationFailedException.cs
- FormCollection.cs
- XdrBuilder.cs
- Rotation3DAnimation.cs
- DragDrop.cs
- FilteredReadOnlyMetadataCollection.cs
- SqlDependencyUtils.cs
- KeyboardNavigation.cs
- MessageBox.cs
- RoutedUICommand.cs
- ScriptingProfileServiceSection.cs
- DocumentSequence.cs
- EntityProviderServices.cs
- XmlHierarchicalEnumerable.cs
- RefType.cs
- ObjectDataSourceFilteringEventArgs.cs
- HexParser.cs
- KeyProperty.cs
- PrivateUnsafeNativeCompoundFileMethods.cs
- DnsPermission.cs
- TypeBuilder.cs
- LineServicesRun.cs
- PointAnimationClockResource.cs
- KoreanCalendar.cs
- MetadataHelper.cs
- SrgsSubset.cs
- DictionaryEntry.cs
- TabletCollection.cs
- MouseEvent.cs
- NavigationService.cs
- Type.cs
- AssemblyUtil.cs
- XmlEncodedRawTextWriter.cs
- PenThreadWorker.cs
- MatrixTransform.cs
- Point3DConverter.cs
- SecurityElement.cs
- SchemaImporterExtensionElement.cs
- SuppressMessageAttribute.cs
- _SSPIWrapper.cs
- SectionXmlInfo.cs
- PbrsForward.cs
- VisualTarget.cs
- safelink.cs
- ErrorTableItemStyle.cs
- MemoryStream.cs
- StylusPointDescription.cs
- Int16KeyFrameCollection.cs
- StickyNote.cs
- SessionMode.cs
- ComponentDispatcher.cs
- TransformCollection.cs
- AudioFormatConverter.cs
- UserMapPath.cs
- _AutoWebProxyScriptHelper.cs
- TraceEventCache.cs
- XmlReflectionImporter.cs
- WebPartUtil.cs
- RegistrySecurity.cs
- DataObjectEventArgs.cs
- TextRangeEdit.cs
- FileLevelControlBuilderAttribute.cs
- UnsafeNativeMethods.cs
- AudioDeviceOut.cs
- Grant.cs
- AddInToken.cs
- HierarchicalDataBoundControl.cs
- HotCommands.cs
- IncrementalCompileAnalyzer.cs
- DataGridTablesFactory.cs
- CharEntityEncoderFallback.cs
- FontStretches.cs
- QuadTree.cs
- CorrelationTokenTypeConvertor.cs
- SettingsBindableAttribute.cs
- HttpCachePolicyBase.cs
- HttpRequest.cs
- GeneralTransform2DTo3D.cs
- BitArray.cs
- SafeSecurityHandles.cs
- RelationshipSet.cs
- HtmlInputText.cs
- MetadataItemCollectionFactory.cs
- WindowsIdentity.cs
- WasEndpointConfigContainer.cs
- Int16Animation.cs
- RepeaterDataBoundAdapter.cs
- SynchronizedChannelCollection.cs
- MatrixTransform.cs
- ReferenceService.cs