/// <summary> /// Callback on visiting each node in the descendency /// during an inheritable property change /// </summary> private static bool OnInheritablePropertyChanged( DependencyObject d, InheritablePropertyChangeInfo info, bool visitedViaVisualTree) { Debug.Assert(d != null, "Must have non-null current node"); DependencyProperty dp = info.Property; bool inheritanceNode = IsInheritanceNode(d, dp); if (inheritanceNode) { BaseValueSourceInternal oldValueSource = BaseValueSourceInternal.Default; INTERNAL_PropertyStorage storage; if (INTERNAL_PropertyStore.TryGetInheritedPropertyStorage(d, dp, false, out storage)) { oldValueSource = storage.BaseValueSourceInternal; } // If the oldValueSource is of lower precedence than Inheritance // only then do we need to Invalidate the property if (BaseValueSourceInternal.Inherited >= oldValueSource) { if (visitedViaVisualTree && typeof(FrameworkElement).IsInstanceOfType(d)) { DependencyObject logicalParent = ((FrameworkElement)d).Parent; if (logicalParent != null) { DependencyObject visualParent = VisualTreeHelper.GetParent(d); if (visualParent != null && visualParent != logicalParent) { return(false); } } } return(d.SetInheritedValue(dp, info.NewValue, false)); } else { if (storage == null) { // get the storage if we didn't to it ealier. INTERNAL_PropertyStore.TryGetInheritedPropertyStorage(d, dp, true, out storage); } // set the inherited value so that it is known if at some point, // the value of higher precedence that is currently used is removed. // we know that the value of the property is not changing, so we can // skip the call to UpdateEffectiveValue(...) storage.InheritedValue = info.NewValue; return(false); } } return(false); }
internal void OnInheritedPropertyChanged(ref InheritablePropertyChangeInfo info) { if (IsFE) { _fe.RaiseInheritedPropertyChangedEvent(ref info); } else if (IsFCE) { _fce.RaiseInheritedPropertyChangedEvent(ref info); } }
// Token: 0x060064AC RID: 25772 RVA: 0x001C3DC3 File Offset: 0x001C1FC3 internal void OnInheritedPropertyChanged(ref InheritablePropertyChangeInfo info) { if (this.IsFE) { this._fe.RaiseInheritedPropertyChangedEvent(ref info); return; } if (this.IsFCE) { this._fce.RaiseInheritedPropertyChangedEvent(ref info); } }
private static bool UpdateEffectiveValue(INTERNAL_PropertyStorage storage, object newValue, BaseValueSourceInternal newValueSource, bool coerceWithCurrentValue, bool coerceValue, bool clearValue, bool propagateChanges) { global::System.Diagnostics.Debug.Assert((coerceWithCurrentValue == coerceValue && !coerceValue) || coerceValue != coerceWithCurrentValue); bool isCoerceOperation = coerceValue || coerceWithCurrentValue; BaseValueSourceInternal oldBaseValueSource = storage.BaseValueSourceInternal; object oldValue; Expression currentExpr = null; // Compute new value object effectiveValue; BaseValueSourceInternal effectiveValueKind; if (isCoerceOperation) { // Source and base value are unchanged during coercion operation effectiveValue = newValue; effectiveValueKind = oldBaseValueSource; // Get old value before it gets overriden oldValue = GetEffectiveValue(storage); } else { ComputeEffectiveValue(storage, out effectiveValue, out effectiveValueKind); // Check for early exit if effective value is not impacted (if we are doing // a coerce operation, we have to go through the update process) if (effectiveValueKind == oldBaseValueSource && newValueSource < effectiveValueKind) { // value source remains the same. // Exit if the newly set value is of lower precedence than the effective value. return(false); } // Get old value before it gets overriden oldValue = GetEffectiveValue(storage); currentExpr = (storage.IsExpression || storage.IsExpressionFromStyle) ? storage.ModifiedValue.BaseValue as Expression : null; #if USEASSERT // If the current base value is an Expression, it should have been detached by now // Or is the same instance as 'effectiveValue' (this occurs when we update a property bound to a // BindingExpression) global::System.Diagnostics.Debug.Assert(currentExpr == null || !currentExpr.IsAttached || object.ReferenceEquals(currentExpr, effectiveValue), "Binding expression should be detached."); #endif storage.ResetValue(); // Update the base value source storage.BaseValueSourceInternal = effectiveValueKind; } object computedValue; if (!isCoerceOperation) { var newExpr = effectiveValue as Expression; if (newExpr == null) { computedValue = storage.Property.PropertyType == typeof(string) ? effectiveValue?.ToString() : effectiveValue; storage.Value = computedValue; } else { #if USEASSERT global::System.Diagnostics.Debug.Assert(effectiveValueKind == BaseValueSourceInternal.Local || effectiveValueKind == BaseValueSourceInternal.LocalStyle); #endif // If the new Expression is the same as the current one, // the Expression is already attached bool isNewBinding = !object.ReferenceEquals(currentExpr, newExpr); if (isNewBinding) { if (newExpr.IsAttached) { throw new InvalidOperationException(string.Format("Cannot attach an instance of '{0}' multiple times", newExpr.GetType())); } newExpr.OnAttach(storage.Owner, storage.Property); storage.Value = newExpr; // Set the new base value } if (effectiveValueKind == BaseValueSourceInternal.Local) { storage.SetExpressionValue(storage.TypeMetadata.DefaultValue, newExpr); } else { storage.SetExpressionFromStyleValue(storage.TypeMetadata.DefaultValue, newExpr); } // 1- 'isNewBinding == true' means that we are attaching a new Expression. // 2- 'newValue is Expression == true' means that we are re-evaluating an Expression // (usually by calling RefreshExpressionCommon) // 3- Otherwise we are trying to change the value of a TwoWay binding. // In that case we have to preserve the Expression (this is not the case if the first two // situations), hence the following line : computedValue = isNewBinding || newValue is Expression?newExpr.GetValue(storage.Owner, storage.Property) : newValue; computedValue = storage.Property.PropertyType == typeof(string) ? computedValue?.ToString() : computedValue; storage.ModifiedValue.ExpressionValue = computedValue; } } else { computedValue = coerceWithCurrentValue ? newValue : GetCoercionBaseValue(storage); if (coerceValue) { storage.ResetCoercedValue(); } } // Coerce to current value if (coerceWithCurrentValue) { object baseValue = GetCoercionBaseValue(storage); ProcessCoerceValue(storage, ref computedValue, oldValue, baseValue, true); } // Coerce Value // We don't want to coerce the value if it's being reset to the property's default value if (storage.TypeMetadata.CoerceValueCallback != null && !(clearValue && storage.FullValueSource == (FullValueSource)BaseValueSourceInternal.Default)) { object baseValue = GetCoercionBaseValue(storage); ProcessCoerceValue(storage, ref computedValue, oldValue, baseValue, false); } // Reset old value inheritance context if (oldBaseValueSource == BaseValueSourceInternal.Local) { // Notes: // - Inheritance context is only handled by local value // - We use null instead of the actual DependencyProperty // as the parameter is ignored in the current implentation. storage.Owner.RemoveSelfAsInheritanceContext(oldValue, null /*storage.Property*/); } // Set new value inheritance context if (effectiveValueKind == BaseValueSourceInternal.Local) { // Check above storage.Owner.ProvideSelfAsInheritanceContext(computedValue, null /*storage.Property*/); } bool valueChanged; if (valueChanged = (storage.INTERNAL_IsVisualValueDirty || !ArePropertiesEqual(oldValue, computedValue, storage.Property.PropertyType))) { // Raise the PropertyChanged event if (!storage.TypeMetadata.Inherits || ShouldRaisePropertyChanged(storage)) { OnPropertyChanged(storage, oldValue, computedValue); } // Propagate to children if property is inherited if (storage.TypeMetadata.Inherits && propagateChanges) { if (storage.Owner is FrameworkElement rootElement) { InheritablePropertyChangeInfo info = new InheritablePropertyChangeInfo(rootElement, storage.Property, oldValue, oldBaseValueSource, computedValue, newValueSource); TreeWalkHelper.InvalidateOnInheritablePropertyChange(rootElement, info); } } storage.INTERNAL_IsVisualValueDirty = false; } // Update the source of the Binding, in case the previous value // of a property was a Binding and the Mode was "TwoWay": // Note: we know that oldBindingExpression.IsUpdating is false // because oldBindingExpression is only set in that case (otherwise, // it is null). if (currentExpr != null) { currentExpr.SetValue(storage.Owner, storage.Property, computedValue); } // Raise the InvalidateMeasure or InvalidateArrange storage.Owner.OnPropertyChanged(new DependencyPropertyChangedEventArgs(oldValue, newValue, storage.Property)); return(valueChanged); }
internal InheritedPropertyChangedEventArgs(ref InheritablePropertyChangeInfo info) { _info = info; }
internal static void InvalidateOnInheritablePropertyChange(FrameworkElement fe, InheritablePropertyChangeInfo info) { if (fe.HasLogicalChildren || (fe.INTERNAL_VisualChildrenInformation != null && fe.INTERNAL_VisualChildrenInformation.Count > 0)) { DescendentsWalker <InheritablePropertyChangeInfo> walker = new DescendentsWalker <InheritablePropertyChangeInfo>( TreeWalkPriority.LogicalTree, InheritablePropertyChangeDelegate, info); walker.StartWalk(fe, true); } #if false if (rootFE != null) { if (rootFE.HasLogicalChildren) { rootFE.IsLogicalChildrenIterationInProgress = true; try { IEnumerator logicalChildren = rootFE.LogicalChildren; if (logicalChildren != null) { while (logicalChildren.MoveNext()) { DependencyObject child = logicalChildren.Current as DependencyObject; if (child != null) { child.SetInheritedValue(info.Property, info.NewValue, true); } } } } finally { rootFE.IsLogicalChildrenIterationInProgress = false; } } } if (rootUIE != null) { if (rootUIE.INTERNAL_VisualChildrenInformation != null) { foreach (UIElement child in rootUIE.INTERNAL_VisualChildrenInformation.Keys) { child.SetInheritedValue(info.Property, info.NewValue, true); } } } #endif // false }
internal static void InvalidateOnInheritablePropertyChange(FrameworkElement fe, InheritablePropertyChangeInfo info) { if (HasChildren(fe)) { DescendentsWalker <InheritablePropertyChangeInfo> walker = new DescendentsWalker <InheritablePropertyChangeInfo>( TreeWalkPriority.LogicalTree, InheritablePropertyChangeDelegate, info); walker.StartWalk(fe, true); } }