Пример #1
0
        /// <summary>
        ///     The common code shared by all variants of SetValue 
        /// </summary> 
        // Takes metadata from caller because most of them have already retrieved it
        //  for their own purposes, avoiding the duplicate GetMetadata call. 
        private void SetValueCommon(
            DependencyProperty  dp,
            object              value,
            PropertyMetadata    metadata, 
            bool                coerceWithDeferredReference,
            bool                coerceWithCurrentValue, 
            OperationType       operationType, 
            bool                isInternal)
        { 
            if (IsSealed)
            {
                throw new InvalidOperationException(SR.Get(SRID.SetOnReadOnlyObjectNotAllowed, this));
            } 

            Expression newExpr = null; 
            DependencySource[] newSources = null; 

            EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 

            // Treat Unset as a Clear
            if( value == DependencyProperty.UnsetValue )
            { 
                // Parameters should have already been validated, so we call
                //  into the private method to avoid validating again. 
                ClearValueCommon(entryIndex, dp, metadata); 
                return;
            } 

            // Validate the "value" against the DP.
            bool isDeferredReference = false;
            bool newValueHasExpressionMarker = (value == ExpressionInAlternativeStore); 

            // First try to validate the value; only after this validation fails should we 
            // do the more expensive checks (type checks) for the less common scenarios 
            if (!newValueHasExpressionMarker)
            { 
                bool isValidValue = isInternal ? dp.IsValidValueInternal(value) : dp.IsValidValue(value);

                // for properties of type "object", we have to always check for expression & deferredreference
                if (!isValidValue || dp.IsObjectType) 
                {
                    // 2nd most common is expression 
                    newExpr = value as Expression; 
                    if (newExpr != null)
                    { 
                        // For Expressions, perform additional validation
                        // Make sure Expression is "attachable"
                        if (!newExpr.Attachable)
                        { 
                            throw new ArgumentException(SR.Get(SRID.SharingNonSharableExpression));
                        } 
 
                        // Check dispatchers of all Sources
                        // CALLBACK 
                        newSources = newExpr.GetSources();
                        ValidateSources(this, newSources, newExpr);
                    }
                    else 
                    {
                        // and least common is DeferredReference 
                        isDeferredReference = (value is DeferredReference); 
                        if (!isDeferredReference)
                        { 
                            if (!isValidValue)
                            {
                                // it's not a valid value & it's not an expression, so throw
                                throw new ArgumentException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 
                            }
                        } 
                    } 
                }
            } 

            // Get old value
            EffectiveValueEntry oldEntry;
            if (operationType == OperationType.ChangeMutableDefaultValue) 
            {
                oldEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Default); 
                oldEntry.Value = value; 
            }
            else 
            {
                oldEntry = GetValueEntry(entryIndex, dp, metadata, RequestFlags.RawEntry);
            }
 
            // if there's an expression in some other store, fetch it now
            Expression currentExpr = 
                    (oldEntry.HasExpressionMarker)  ? _getExpressionCore(this, dp, metadata) 
                  : (oldEntry.IsExpression)         ? (oldEntry.LocalValue as Expression)
                  :                                   null; 

            // Allow expression to store value if new value is
            // not an Expression, if applicable
 
            bool handled = false;
            if ((currentExpr != null) && (newExpr == null)) 
            { 
                // Resolve deferred references because we haven't modified
                // the expression code to work with DeferredReference yet. 
                if (isDeferredReference)
                {
                    value = ((DeferredReference) value).GetValue(BaseValueSourceInternal.Local);
                } 

                // CALLBACK 
                handled = currentExpr.SetValue(this, dp, value); 
                entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex);
            } 

            // Create the new effective value entry
            EffectiveValueEntry newEntry;
            if (handled) 
            {
                // If expression handled set, then done 
                if (entryIndex.Found) 
                {
                    newEntry = _effectiveValues[entryIndex.Index]; 
                }
                else
                {
                    // the expression.SetValue resulted in this value being removed from the table; 
                    // use the default value.
                    newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 
                } 

                coerceWithCurrentValue = false; // expression already handled the control-value 
            }
            else
            {
                // allow a control-value to coerce an expression value, when the 
                // expression didn't handle the value
                if (coerceWithCurrentValue && currentExpr != null) 
                { 
                    currentExpr = null;
                } 

                newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Local);

                // detach the old expression, if applicable 
                if (currentExpr != null)
                { 
                    // CALLBACK 
                    DependencySource[] currentSources = currentExpr.GetSources();
 
                    UpdateSourceDependentLists(this, dp, currentSources, currentExpr, false);  // Remove

                    // CALLBACK
                    currentExpr.OnDetach(this, dp); 
                    currentExpr.MarkDetached();
                    entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 
                } 

                // attach the new expression, if applicable 
                if (newExpr == null)
                {
                    // simple local value set
                    newEntry.HasExpressionMarker = newValueHasExpressionMarker; 
                    newEntry.Value = value;
                } 
                else 
                {
                    Debug.Assert(!coerceWithCurrentValue, "Expression values not supported in SetCurrentValue"); 

                    // First put the expression in the effectivevalueentry table for this object;
                    // this allows the expression to update the value accordingly in OnAttach
                    SetEffectiveValue(entryIndex, dp, dp.GlobalIndex, metadata, newExpr, BaseValueSourceInternal.Local); 

                    // Before the expression is attached it has default value 
                    object defaultValue = metadata.GetDefaultValue(this, dp); 
                    entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex);
                    SetExpressionValue(entryIndex, defaultValue, newExpr); 
                    UpdateSourceDependentLists(this, dp, newSources, newExpr, true);  // Add

                    newExpr.MarkAttached();
 
                    // CALLBACK
                    newExpr.OnAttach(this, dp); 
 
                    // the attach may have added entries in the effective value table ...
                    // so, update the entryIndex accordingly. 
                    entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex);

                    newEntry = EvaluateExpression(
                            entryIndex, 
                            dp,
                            newExpr, 
                            metadata, 
                            oldEntry,
                            _effectiveValues[entryIndex.Index]); 

                    entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex);
                }
            } 

            UpdateEffectiveValue( 
                entryIndex, 
                dp,
                metadata, 
                oldEntry,
                ref newEntry,
                coerceWithDeferredReference,
                coerceWithCurrentValue, 
                operationType);
        }