Пример #1
0
        internal void SetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry newEntry, EffectiveValueEntry oldEntry) 
        {
            if (metadata != null && 
                metadata.IsInherited && 
                (newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Inherited ||
                    newEntry.IsCoerced || newEntry.IsAnimated) && 
                !IsSelfInheritanceParent)
            {
                SetIsSelfInheritanceParent();
                entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 
            }
 
            bool restoreMarker = false; 

            if (oldEntry.HasExpressionMarker && !newEntry.HasExpressionMarker) 
            {
                BaseValueSourceInternal valueSource = newEntry.BaseValueSourceInternal;
                restoreMarker = (valueSource == BaseValueSourceInternal.ThemeStyle ||
                                 valueSource == BaseValueSourceInternal.ThemeStyleTrigger || 
                                 valueSource == BaseValueSourceInternal.Style ||
                                 valueSource == BaseValueSourceInternal.TemplateTrigger || 
                                 valueSource == BaseValueSourceInternal.StyleTrigger || 
                                 valueSource == BaseValueSourceInternal.ParentTemplate ||
                                 valueSource == BaseValueSourceInternal.ParentTemplateTrigger); 
            }

            if (restoreMarker)
            { 
                newEntry.RestoreExpressionMarker();
            } 
            else if (oldEntry.IsExpression && oldEntry.ModifiedValue.ExpressionValue == Expression.NoValue) 
            {
                // we now have a value for an expression that is "hiding" - save it 
                // as the expression value
                newEntry.SetExpressionValue(newEntry.Value, oldEntry.ModifiedValue.BaseValue);
            }
 
#if DEBUG
            object baseValue; 
            if (!newEntry.HasModifiers) 
            {
                baseValue = newEntry.Value; 
            }
            else
            {
                if (newEntry.IsCoercedWithCurrentValue) 
                {
                    baseValue = newEntry.ModifiedValue.CoercedValue; 
                } 
                else if (newEntry.IsExpression)
                { 
                    baseValue = newEntry.ModifiedValue.ExpressionValue;
                }
                else
                { 
                    baseValue = newEntry.ModifiedValue.BaseValue;
                } 
            } 

            Debug.Assert(newEntry.IsDeferredReference == (baseValue is DeferredReference)); 
#endif

            if (entryIndex.Found)
            { 
                _effectiveValues[entryIndex.Index] = newEntry;
            } 
            else 
            {
                InsertEntry(newEntry, entryIndex.Index); 
                if (metadata != null && metadata.IsInherited)
                {
                    InheritableEffectiveValuesCount++;
                } 
            }
 
            Debug.Assert(dp == null || (dp.GlobalIndex == newEntry.PropertyIndex), "EffectiveValueEntry & DependencyProperty do not match"); 
        }
Пример #2
0
        [FriendAccessAllowed] // Declared in Base also used in Framework 
        internal UpdateResult UpdateEffectiveValue(
                EntryIndex          entryIndex,
                DependencyProperty  dp,
                PropertyMetadata    metadata, 
                EffectiveValueEntry oldEntry,
            ref EffectiveValueEntry newEntry, 
                bool                coerceWithDeferredReference, 
                bool                coerceWithCurrentValue,
                OperationType       operationType) 
        {
            if (dp == null)
            {
                throw new ArgumentNullException("dp"); 
            }
 
#region EventTracing 
#if VERBOSE_PROPERTY_EVENT
            bool isDynamicTracing = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose); // This was under "normal" 
            if (isDynamicTracing)
            {
                ++InvalidationCount;
                if( InvalidationCount % 100 == 0 ) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, 
                                                         MS.Utility.EventType.Info, 
                                                         InvalidationCount );
                } 

                string TypeAndName = String.Format(CultureInfo.InvariantCulture, "[{0}]{1}({2})",GetType().Name,dp.Name,base.GetHashCode()); // FxCop wanted the CultureInfo.InvariantCulture

                EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, 
                                                     MS.Utility.EventType.StartEvent,
                                                     base.GetHashCode(), TypeAndName); // base.GetHashCode() to avoid calling a virtual, which FxCop doesn't like. 
            } 
#endif
 

#endregion EventTracing

#if NESTED_OPERATIONS_CHECK 
            // Are we invalidating out of control?
            if( NestedOperations > NestedOperationMaximum ) 
            { 
                // We're invalidating out of control, time to abort.
                throw new InvalidOperationException("Too many levels of nested DependencyProperty invalidations.  This usually indicates a circular reference in the application and the cycle needs to be broken."); 
            }
            NestedOperations++; // Decrement in the finally block
#endif
            int targetIndex = dp.GlobalIndex; 

            if (oldEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown) 
            { 
                // Do a full get value of the old entry if it isn't supplied.
                // It isn't supplied in cases where we are *unsetting* a value 
                // (e.g. ClearValue, style unapply, trigger unapply)
                oldEntry = GetValueEntry(
                                    entryIndex,
                                    dp, 
                                    metadata,
                                    RequestFlags.RawEntry); 
            } 

            object oldValue = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 


            /*
            if( TraceDependencyProperty.IsEnabled ) 
            {
                TraceDependencyProperty.Trace( 
                    TraceEventType.Verbose, 
                    TraceDependencyProperty.UpdateEffectiveValueStart,
                    this, 
                    dp,
                    dp.OwnerType,
                    oldValue,
                    oldEntry.BaseValueSourceInternal ); 
            }
            */ 
 
            // for control-value coercion, extract the desired control value, then
            // reset the new entry to ask for a re-evaluation with coercion 
            object controlValue = null;
            if (coerceWithCurrentValue)
            {
                controlValue = newEntry.Value; 
                newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced);
            } 
 
            // check for early-out opportunities:
            //  1) the new entry is of lower priority than the current entry 
            if ((newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Unknown) &&
                (newEntry.BaseValueSourceInternal < oldEntry.BaseValueSourceInternal))
            {
                return 0; 
            }
 
            bool isReEvaluate = false; 
            bool isCoerceValue = false;
            bool isClearValue = false; 

            if (newEntry.Value == DependencyProperty.UnsetValue)
            {
                FullValueSource fullValueSource = newEntry.FullValueSource; 
                isCoerceValue = (fullValueSource == FullValueSource.IsCoerced);
                isReEvaluate = true; 
 
                if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Local)
                { 
                    isClearValue = true;
                }
            }
 
            // if we're not in an animation update (caused by AnimationStorage.OnCurrentTimeInvalidated)
            // then always force a re-evaluation if (a) there was an animation in play or (b) there's 
            // an expression evaluation to be made 
            if (isReEvaluate ||
                (!newEntry.IsAnimated && 
                 (oldEntry.IsAnimated ||
                 (oldEntry.IsExpression && newEntry.IsExpression && (newEntry.ModifiedValue.BaseValue == oldEntry.ModifiedValue.BaseValue)))))
            {
                // we have to compute the new value 
                if (!isCoerceValue)
                { 
                    newEntry = EvaluateEffectiveValue(entryIndex, dp, metadata, oldEntry, newEntry, operationType); 

                    // Make sure that the call out did not cause a change to entryIndex 
                    entryIndex = CheckEntryIndex(entryIndex, targetIndex);

                    bool found = (newEntry.Value != DependencyProperty.UnsetValue);
                    if (!found && metadata.IsInherited) 
                    {
                        DependencyObject inheritanceParent = InheritanceParent; 
                        if (inheritanceParent != null) 
                        {
                            // Fetch the IsDeferredValue flag from the InheritanceParent 
                            EntryIndex parentEntryIndex = inheritanceParent.LookupEntry(dp.GlobalIndex);
                            if (parentEntryIndex.Found)
                            {
                                found = true; 
                                newEntry = inheritanceParent._effectiveValues[parentEntryIndex.Index].GetFlattenedEntry(RequestFlags.FullyResolved);
                                newEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited; 
                            } 
                        }
                    } 

                    // interesting that I just had to add this ... suggests that we are now overinvalidating
                    if (!found)
                    { 
                        newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp));
                    } 
                } 
                else
                { 
                    if (!oldEntry.HasModifiers)
                    {
                        newEntry = oldEntry;
                    } 
                    else
                    { 
                        newEntry = new EffectiveValueEntry(dp, oldEntry.BaseValueSourceInternal); 
                        ModifiedValue modifiedValue = oldEntry.ModifiedValue;
                        object baseValue = modifiedValue.BaseValue; 
                        newEntry.Value = baseValue;
                        newEntry.HasExpressionMarker = oldEntry.HasExpressionMarker;

                        if (oldEntry.IsExpression) 
                        {
                            newEntry.SetExpressionValue(modifiedValue.ExpressionValue, baseValue); 
                        } 

                        if (oldEntry.IsAnimated) 
                        {
                            newEntry.SetAnimatedValue(modifiedValue.AnimatedValue, baseValue);
                        }
                    } 
                }
            } 
 
            // Coerce to current value
            if (coerceWithCurrentValue) 
            {
                object baseValue = newEntry.GetFlattenedEntry(RequestFlags.CoercionBaseValue).Value;

                ProcessCoerceValue( 
                    dp,
                    metadata, 
                    ref entryIndex, 
                    ref targetIndex,
                    ref newEntry, 
                    ref oldEntry,
                    ref oldValue,
                    baseValue,
                    controlValue, 
                    null /*coerceValueCallback */,
                    coerceWithDeferredReference, 
                    coerceWithCurrentValue, 
                    false /*skipBaseValueChecks*/);
 
                // Make sure that the call out did not cause a change to entryIndex
                entryIndex = CheckEntryIndex(entryIndex, targetIndex);
            }
 
            // Coerce Value
            if (metadata.CoerceValueCallback != null && 
                !(isClearValue && newEntry.FullValueSource == (FullValueSource)BaseValueSourceInternal.Default)) 
            {
                // CALLBACK 
                object baseValue = newEntry.GetFlattenedEntry(RequestFlags.CoercionBaseValue).Value;

                ProcessCoerceValue(
                    dp, 
                    metadata,
                    ref entryIndex, 
                    ref targetIndex, 
                    ref newEntry,
                    ref oldEntry, 
                    ref oldValue,
                    baseValue,
                    null /* controlValue */,
                    metadata.CoerceValueCallback, 
                    coerceWithDeferredReference,
                    false /* coerceWithCurrentValue */, 
                    false /*skipBaseValueChecks*/); 

                // Make sure that the call out did not cause a change to entryIndex 
                entryIndex = CheckEntryIndex(entryIndex, targetIndex);
            }

            // The main difference between this callback and the metadata.CoerceValueCallback is that 
            // designers want to be able to coerce during all value changes including a change to the
            // default value. Whereas metadata.CoerceValueCallback coerces all property values but the 
            // default, because default values are meant to fit automatically fit into the coersion constraint. 

            if (dp.DesignerCoerceValueCallback != null) 
            {
                // During a DesignerCoerceValueCallback the value obtained is stored in the same
                // member as the metadata.CoerceValueCallback. In this case we do not store the
                // baseValue in the entry. Thus the baseValue checks will the violated. That is the 
                // reason for skipping these checks in this one case.
 
                // Also before invoking the DesignerCoerceValueCallback the baseValue must 
                // always be expanded if it is a DeferredReference
 
                ProcessCoerceValue(
                    dp,
                    metadata,
                    ref entryIndex, 
                    ref targetIndex,
                    ref newEntry, 
                    ref oldEntry, 
                    ref oldValue,
                    newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value, 
                    null /*controlValue*/,
                    dp.DesignerCoerceValueCallback,
                    false /*coerceWithDeferredReference*/,
                    false /*coerceWithCurrentValue*/, 
                    true /*skipBaseValueChecks*/);
 
                // Make sure that the call out did not cause a change to entryIndex 
                entryIndex = CheckEntryIndex(entryIndex, targetIndex);
            } 

            UpdateResult result = 0;

            if (newEntry.FullValueSource != (FullValueSource) BaseValueSourceInternal.Default) 
            {
                Debug.Assert(newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Unknown, "Value source should be known at this point"); 
                bool unsetValue = false; 

                if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Inherited) 
                {
                    if (DependencyObject.IsTreeWalkOperation(operationType) &&
                        (newEntry.IsCoerced || newEntry.IsAnimated))
                    { 
                        // an inherited value has been coerced or animated.  This
                        // should be treated as a new "set" of the property. 
                        // The current tree walk should not continue into the subtree, 
                        // but rather a new tree walk should start.
 
                        // this signals OnPropertyChanged to start a new tree walk
                        // and mark the current node as SelfInheritanceParent
                        operationType = OperationType.Unknown;
 
                        // this signals the caller not to continue the current
                        // tree walk into the subtree 
                        result |= UpdateResult.InheritedValueOverridden; 
                    }
                    else if (!IsSelfInheritanceParent) 
                    {
                        // otherwise, just inherit the value from the InheritanceParent
                        unsetValue = true;
                    } 
                }
 
                if (unsetValue) 
                {
                    UnsetEffectiveValue(entryIndex, dp, metadata); 
                }
                else
                {
                    SetEffectiveValue(entryIndex, dp, metadata, newEntry, oldEntry); 
                }
            } 
            else 
            {
                UnsetEffectiveValue(entryIndex, dp, metadata); 
            }

            // Change notifications are fired when the value actually changed or in
            // the case of the Freezable mutable factories when the value source changes. 
            // Try AvaCop without the second condition to repro this problem.
            bool isAValueChange = !Equals(dp, oldValue, newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value); 
 
            if (isAValueChange)
            { 
                result |= UpdateResult.ValueChanged;
            }

            if (isAValueChange || 
                (operationType == OperationType.ChangeMutableDefaultValue && oldEntry.BaseValueSourceInternal != newEntry.BaseValueSourceInternal) ||
                (metadata.IsInherited && oldEntry.BaseValueSourceInternal != newEntry.BaseValueSourceInternal && operationType != OperationType.AddChild && operationType != OperationType.RemoveChild && operationType != OperationType.Inherit)) 
            { 
                result |= UpdateResult.NotificationSent;
 
                try
                {
                    // fire change notification
                    NotifyPropertyChange( 
                            new DependencyPropertyChangedEventArgs(
                                    dp, 
                                    metadata, 
                                    isAValueChange,
                                    oldEntry, 
                                    newEntry,
                                    operationType));
                }
                finally 
                {
#if NESTED_OPERATIONS_CHECK 
                    NestedOperations--; 
#endif
                } 
            }

#region EventTracing
#if VERBOSE_PROPERTY_EVENT 
            if (isDynamicTracing)
            { 
                if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
                {
                    EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, MS.Utility.EventType.EndEvent); 
                }
            }
#endif
#endregion EventTracing 

 
            /* 
            if( TraceDependencyProperty.IsEnabled )
            { 
                TraceDependencyProperty.Trace(
                    TraceEventType.Verbose,
                    TraceDependencyProperty.UpdateEffectiveValueStop,
                    this, dp, dp.OwnerType, 
                    newEntry.Value, newEntry.BaseValueSourceInternal );
            } 
            */ 

            // There are two cases in which we need to adjust inheritance contexts: 
            //
            //     1.  The value pointed to this DP has changed, in which case
            //         we need to move the context from the old value to the
            //         new value. 
            //
            //     2.  The value has not changed, but the ValueSource for the 
            //         property has.  (For example, we've gone from being a local 
            //         value to the result of a binding expression that just
            //         happens to return the same DO instance.)  In which case 
            //         we may need to add or remove contexts even though we
            //         did not raise change notifications.
            //
            // We don't want to provide an inheritance context if the entry is 
            // animated, coerced, is an expression, is coming from a style or
            // template, etc.  To avoid this, we explicitly check that the 
            // FullValueSource is Local.  By checking FullValueSource rather than 
            // BaseValueSource we are implicitly filtering out any sources which
            // have modifiers.  (e.g., IsExpression, IsAnimated, etc.) 

            bool oldEntryHadContext = oldEntry.FullValueSource == (FullValueSource) BaseValueSourceInternal.Local;
            bool newEntryNeedsContext = newEntry.FullValueSource == (FullValueSource) BaseValueSourceInternal.Local;
 
            // NOTE:  We use result rather than isAValueChange below so that we
            //        pick up mutable default promotion, etc. 
            if (result != 0 || (oldEntryHadContext != newEntryNeedsContext)) 
            {
                if (oldEntryHadContext) 
                {
                    // RemoveSelfAsInheritanceContext no-ops null, non-DO values, etc.
                    RemoveSelfAsInheritanceContext(oldEntry.LocalValue, dp);
                } 

                // Become the context for the new value. This is happens after 
                // invalidation so that FE has a chance to hookup the logical 
                // tree first. This is done only if the current DependencyObject
                // wants to be in the InheritanceContext tree. 
                if (newEntryNeedsContext)
                {
                    // ProvideSelfAsInheritanceContext no-ops null, non-DO values, etc.
                    ProvideSelfAsInheritanceContext(newEntry.LocalValue, dp); 
                }
 
                // DANGER:  Callout might add/remove entries in the effective value table. 
                //          Uncomment the following if you need to use entryIndex post
                //          context hookup. 
                //
                // entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex);
            }
 
            return result;
        } 
Пример #3
0
        private EffectiveValueEntry EvaluateExpression( 
            EntryIndex entryIndex,
            DependencyProperty dp, 
            Expression expr,
            PropertyMetadata metadata,
            EffectiveValueEntry oldEntry,
            EffectiveValueEntry newEntry) 
        {
            object value = expr.GetValue(this, dp); 
            bool isDeferredReference = false; 

            if (value != DependencyProperty.UnsetValue && value != Expression.NoValue) 
            {
                isDeferredReference = (value is DeferredReference);
                if (!isDeferredReference && !dp.IsValidValue(value))
                { 
#region EventTracing
#if VERBOSE_PROPERTY_EVENT 
                    if (isDynamicTracing) 
                    {
                        if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 
                        {
                            EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYGUID,
                                                                MS.Utility.EventType.EndEvent,
                                                                EventTrace.PROPERTYVALIDATION, 0xFFF ); 
                        }
                    } 
#endif 
#endregion EventTracing
                    throw new InvalidOperationException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 
                }
            }
            else
            { 
                if (value == Expression.NoValue)
                { 
                    // The expression wants to "hide".  First set the 
                    // expression value to NoValue to indicate "hiding".
                    newEntry.SetExpressionValue(Expression.NoValue, expr); 

                    // Next, get the expression value some other way.
                    if (!dp.ReadOnly)
                    { 
                        EvaluateBaseValueCore(dp, metadata, ref newEntry);
                        value = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 
                    } 
                    else
                    { 
                        value = DependencyProperty.UnsetValue;
                    }
                }
 
                // if there is still no value, use the default
                if (value == DependencyProperty.UnsetValue) 
                { 
                    value = metadata.GetDefaultValue(this, dp);
                } 
            }

            // Set the expr and its evaluated value into
            // the _effectiveValues cache 
            newEntry.SetExpressionValue(value, expr);
            return newEntry; 
        } 
Пример #4
0
        //
        //  This method
        //  1. Retrieves an instance value from per-instance StyleData.
        //  2. Creates the StyleData if this is the first request.
        //
        internal static object GetInstanceValue(
            UncommonField<HybridDictionary []>  dataField,
            DependencyObject            container,
            FrameworkElement            feChild,
            FrameworkContentElement     fceChild,
            int                         childIndex,
            DependencyProperty          dp,
            int                         i,
            ref EffectiveValueEntry     entry)
        {
            object rawValue = entry.Value;
            DependencyObject child = null;

            FrameworkElement feContainer;
            FrameworkContentElement fceContainer;
            Helper.DowncastToFEorFCE(container, out feContainer, out fceContainer, true);

            HybridDictionary[] styleData = (dataField != null) ? dataField.GetValue(container) : null;
            HybridDictionary instanceValues = (styleData != null) ? styleData[(int)InstanceStyleData.InstanceValues] : null;
            InstanceValueKey key = new InstanceValueKey(childIndex, dp.GlobalIndex, i);

            object value = (instanceValues != null)? instanceValues[key] : null;
            bool isRequestingExpression = (feChild != null) ? feChild.IsRequestingExpression : fceChild.IsRequestingExpression;

            if (value == null)
            {
                value = NotYetApplied;
            }

            // if the value is a detached expression, replace it with a new one
            Expression expr = value as Expression;
            if (expr != null && expr.HasBeenDetached)
            {
                value = NotYetApplied;
            }

            // if this is the first request, create the value
            if (value == NotYetApplied)
            {
                child = feChild;
                if (child == null)
                    child = fceChild;

                MarkupExtension me;
                Freezable freezable;

                if ((me = rawValue as MarkupExtension) != null)
                {
                    // exception:  if the child is not yet initialized and the request
                    // is for an expression, don't create the value.  This gives the parser
                    // a chance to set local values, to override the style-defined values.
                    if (isRequestingExpression)
                    {
                        bool isInitialized = (feChild != null) ? feChild.IsInitialized : fceChild.IsInitialized;
                        if (!isInitialized)
                        {
                            return DependencyProperty.UnsetValue;
                        }
                    }

                    ProvideValueServiceProvider provideValueServiceProvider = new ProvideValueServiceProvider();
                    provideValueServiceProvider.SetData( child, dp );
                    value = me.ProvideValue(provideValueServiceProvider);
                }
                else if ((freezable = rawValue as Freezable) != null)
                {
                    value = freezable.Clone();
                    child.ProvideSelfAsInheritanceContext(value, dp);
                }

                // store it in per-instance StyleData (even if it's DependencyProperty.UnsetValue)
                Debug.Assert(value != NotYetApplied, "attempt to retrieve instance value that was never set");
                instanceValues[key] = value;

                if (value != DependencyProperty.UnsetValue)
                {
                    expr = value as Expression;
                    // if the instance value is an expression, attach it
                    if (expr != null)
                    {
                        expr.OnAttach(child, dp);
                    }
                }
            }

            // if the value is an Expression (and we're being asked for the real value),
            // delegate to the expression.
            if (expr != null)
            {
                if (!isRequestingExpression)
                {
                    if (child == null)
                    {
                        child = feChild;
                        if (child == null)
                            child = fceChild;
                    }

                    entry.ResetValue(DependencyObject.ExpressionInAlternativeStore, true);
                    entry.SetExpressionValue(expr.GetValue(child, dp), DependencyObject.ExpressionInAlternativeStore);
                }
                else
                {
                    entry.Value = value;
                }
            }
            else
            {
                entry.Value = value;
            }

            return value;
        }