internal static void ValidateSources(DependencyObject d, DependencySource[] newSources, Expression expr) { // Make sure all Sources are owned by the same thread. if (newSources != null) { Dispatcher dispatcher = d.Dispatcher; for (int i = 0; i < newSources.Length; i++) { Dispatcher sourceDispatcher = newSources[i].DependencyObject.Dispatcher; if (sourceDispatcher != dispatcher && !(expr.SupportsUnboundSources && sourceDispatcher == null)) { throw new ArgumentException(SR.Get(SRID.SourcesMustBeInSameThread)); } } } }
internal static void UpdateSourceDependentLists(DependencyObject d, DependencyProperty dp, DependencySource[] sources, Expression expr, bool add) { // Sources already validated to be on the same thread as Dependent (d) if (sources != null) { // don't hold a reference on the dependent if the expression is doing // the invalidations. This helps avoid memory leaks (bug 871139) if (expr.ForwardsInvalidations) { d = null; dp = null; } for (int i = 0; i < sources.Length; i++) { DependencySource source = sources[i]; // A Sealed DependencyObject does not have a Dependents list // so don't bother updating it (or attempt to add one). Debug.Assert((!source.DependencyObject.IsSealed) || (DependentListMapField.GetValue(source.DependencyObject) == default(object))); if (!source.DependencyObject.IsSealed) { // Retrieve the DependentListMap for this source // The list of dependents to invalidate is stored using a special negative key FrugalMap dependentListMap; object value = DependentListMapField.GetValue(source.DependencyObject); if (value != null) { dependentListMap = (FrugalMap)value; } else { dependentListMap = new FrugalMap(); } // Get list of DependentList off of ID map of Source object dependentListObj = dependentListMap[source.DependencyProperty.GlobalIndex]; Debug.Assert(dependentListObj != null, "dependentList should either be unset or non-null"); // Add/Remove new Dependent (this) to Source's list if (add) { DependentList dependentList; if (dependentListObj == DependencyProperty.UnsetValue) { dependentListMap[source.DependencyProperty.GlobalIndex] = dependentList = new DependentList(); } else { dependentList = (DependentList)dependentListObj; } dependentList.Add(d, dp, expr); } else { if (dependentListObj != DependencyProperty.UnsetValue) { DependentList dependentList = (DependentList)dependentListObj; dependentList.Remove(d, dp, expr); if (dependentList.IsEmpty) { // No more dependencies for this property; reclaim the space if we can. dependentListMap[source.DependencyProperty.GlobalIndex] = DependencyProperty.UnsetValue; } } } // Set the updated struct back into the source's _localStore. DependentListMapField.SetValue(source.DependencyObject, dependentListMap); } } } }
// // Changes the sources of an existing Expression // internal static void ChangeExpressionSources(Expression expr, DependencyObject d, DependencyProperty dp, DependencySource[] newSources) { if (!expr.ForwardsInvalidations) { // Get current local value (should be provided Expression) // (No need to go through read local callback, just checking // for presence of Expression) EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex); if (!entryIndex.Found || (d._effectiveValues[entryIndex.Index].LocalValue != expr)) { throw new ArgumentException(SR.Get(SRID.SourceChangeExpressionMismatch)); } } // Get current sources // CALLBACK DependencySource[] currentSources = expr.GetSources(); // Remove old if (currentSources != null) { UpdateSourceDependentLists(d, dp, currentSources, expr, false); // Remove } // Add new if (newSources != null) { UpdateSourceDependentLists(d, dp, newSources, expr, true); // Add } }
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; }
internal void InvalidateLocalBindings () { if (expressions == null || expressions.Count == 0) return; if (invalidatingLocalBindings) return; invalidatingLocalBindings = true; DependencyProperty[] keys = new DependencyProperty [expressions.Keys.Count]; Expression[] values = new Expression [expressions.Values.Count]; expressions.Keys.CopyTo (keys, 0); expressions.Values.CopyTo (values, 0); for (int i = 0; i < keys.Length; i ++) { if (values[i] is BindingExpressionBase) { BindingExpressionBase beb = (BindingExpressionBase) values[i]; beb.Invalidate (); SetValue (keys[i], beb); } } invalidatingLocalBindings = false; }