WPF依赖对象(DependencyObject) 实现源码,理解WPF原理必读
/// DependencyObject encompasses all property engine services. It's primary function
/// is providing facilities to compute a property's value based on other properties.<para/>
///
/// The Property Engine introduces a new type of property: attached properties. Attached
/// properties are identified via <see cref="DependencyProperty"/> and are read and
/// written using GetValue and SetValue.<para/>
///
/// Attached properties may be set and queried on any DependencyObject-derived type.<para/>
///
/// <see cref="Expression"/> is used to define relationships between properties. SetValue
/// is used to apply the Expression to the property on the instance.
1 // #define NESTED_OPERATIONS_ 2 3 using System; 4 using System.Collections; 5 using System.Diagnostics; 6 using System.Globalization; // For CultureInfo.InvariantCulture 7 using System.Reflection; 8 using System.Security.Permissions; // For LinkDemand 9 10 using System.Windows.Threading; 11 12 using MS.Utility; 13 using MS.Internal; 14 using MS.Internal.WindowsBase; 15 using System.Windows.Markup; 16 17 namespace System.Windows 18 { 19 /// <summary> 20 /// DependencyObject is an object that participates in the property dependency system 21 /// </summary> 22 /// <remarks> 23 24 /// 25 /// DependencyObject services include the following: 26 /// <para/> 27 /// <list type="bullet"> 28 /// <item>Dependency-based property value evaluation through Expressions</item> 29 /// <item>Property invalidation dependent traversal through Expressions</item> 30 /// <item>Attached property support</item> 31 /// <item>Invalidation notification services</item> 32 /// </list> 33 /// </remarks> 34 /// This attribute allows designers looking at metadata through TypeDescriptor to see dependency properties 35 /// and attached properties. 36 [System.ComponentModel.TypeDescriptionProvider(typeof(MS.Internal.ComponentModel.DependencyObjectProvider))] 37 [System.Windows.Markup.NameScopeProperty("NameScope", typeof(System.Windows.NameScope))] 38 public class DependencyObject : DispatcherObject 39 { 40 /// <summary> 41 /// Default DependencyObject constructor 42 /// </summary> 43 /// <remarks> 44 /// Automatic determination of current Dispatcher. Use alternative constructor 45 /// that accepts a Dispatcher for best performance. 46 /// </remarks> 47 public DependencyObject() 48 { 49 Initialize(); 50 } 51 52 /// <summary>Returns the DType that represents the CLR type of this instance</summary> 53 public DependencyObjectType DependencyObjectType 54 { 55 get 56 { 57 if (_dType == null) 58 { 59 // Specialized type identification 60 _dType = DependencyObjectType.FromSystemTypeInternal(GetType()); 61 } 62 63 // Do not call VerifyAccess because this method is trivial. 64 return _dType; 65 } 66 } 67 68 private void Initialize() 69 { 70 CanBeInheritanceContext = true; 71 CanModifyEffectiveValues = true; 72 } 73 74 /// <summary> 75 /// Makes this object Read-Only state of this object; when in a Read-Only state, SetValue is not permitted, 76 /// though the effective value for a property may change. 77 /// </summary> 78 [FriendAccessAllowed] // Built into Base, also used by Framework. 79 internal virtual void Seal() 80 { 81 Debug.Assert(!(this is Freezable), "A Freezable should not call DO's implementation of Seal()"); 82 83 // Currently DependencyObject.Seal() is semantically different than Freezable.Freeze(). 84 // Though freezing implies sealing the reverse isn't true. The salient difference 85 // here is that sealing a DependencyObject does not force all DPs on that object to 86 // also be sealed. Thus, when we Seal(), we promote all cached values to locally set 87 // so that the user can continue to modify them. Freezable types instead strip off 88 // the promotion handler and freeze the cached default. Note that when / if we make 89 // Seal() == Freeze this code should go away in favor of the behavior used for Freezables. 90 PropertyMetadata.PromoteAllCachedDefaultValues(this); 91 92 // Since Freeze doesn't call Seal the code below will also be duplicated in Freeze(). 93 94 // Since this object no longer changes it won't be able to notify dependents 95 DependentListMapField.ClearValue(this); 96 97 DO_Sealed = true; 98 } 99 100 /// <summary> 101 /// Indicates whether or not this object is in a Read-Only state; when in a Read-Only state, SetValue is not permitted, 102 /// though the effective value for a property may change. 103 /// </summary> 104 public bool IsSealed 105 { 106 get 107 { 108 return DO_Sealed; 109 } 110 } 111 112 /// <summary> 113 /// We override Equals() to seal it to prevent custom Equals() 114 /// implementations. 115 /// 116 /// There are only two scenarios where overriding Equals makes 117 /// sense: 118 /// 119 /// 1. You are a value type (passed by copy). 120 /// 2. You are an immutable reference type (e.g., System.String). 121 /// 122 /// Otherwise you are going to cause problems with keyed and 123 /// some types of sorted datastructures because your values 124 /// can mutate to be equals or not equals while they reside in 125 /// the store (bad news for System.Collections(.Generic)). 126 /// 127 /// Furthermore, defining equality for two DOs is a very slippery 128 /// slope. Are two brushes "equal" if they both paint red? What 129 /// if one is only red this frame because it is animated? What if 130 /// one is databound? What if one is frozen? ...and so on. 131 /// 132 /// Since a DO can never be immutable (attached properties, etc.) 133 /// it makes sense to disallow overriding of Equals. 134 /// </summary> 135 public override sealed bool Equals(Object obj) 136 { 137 return base.Equals(obj); 138 } 139 140 /// <summary> 141 /// CS0659: Required when overriding Equals(). Overriding 142 /// GetHashCode() is a bad idea for similar reasons. 143 /// </summary> 144 public override sealed int GetHashCode() 145 { 146 return base.GetHashCode(); 147 } 148 149 /// <summary> 150 /// Retrieve the value of a property 151 /// </summary> 152 /// <param name="dp">Dependency property</param> 153 /// <returns>The computed value</returns> 154 public object GetValue(DependencyProperty dp) 155 { 156 // Do not allow foreign threads access. 157 // (This is a noop if this object is not assigned to a Dispatcher.) 158 // 159 this.VerifyAccess(); 160 161 if (dp == null) 162 { 163 throw new ArgumentNullException("dp"); 164 } 165 166 // Call Forwarded 167 return GetValueEntry( 168 LookupEntry(dp.GlobalIndex), 169 dp, 170 null, 171 RequestFlags.FullyResolved).Value; 172 } 173 174 /// <summary> 175 /// This overload of GetValue returns UnsetValue if the property doesn't 176 /// have an entry in the _effectiveValues. This way we will avoid inheriting 177 /// the default value from the parent. 178 /// </summary> 179 [FriendAccessAllowed] // Built into Base, also used by Core. 180 internal EffectiveValueEntry GetValueEntry( 181 EntryIndex entryIndex, 182 DependencyProperty dp, 183 PropertyMetadata metadata, 184 RequestFlags requests) 185 { 186 EffectiveValueEntry entry; 187 188 if (dp.ReadOnly) 189 { 190 if (metadata == null) 191 { 192 metadata = dp.GetMetadata(DependencyObjectType); 193 } 194 195 GetReadOnlyValueCallback getValueCallback = metadata.GetReadOnlyValueCallback; 196 if (getValueCallback != null) 197 { 198 BaseValueSourceInternal valueSource; 199 entry = new EffectiveValueEntry(dp); 200 entry.Value = getValueCallback(this, out valueSource); 201 entry.BaseValueSourceInternal = valueSource; 202 return entry; 203 } 204 } 205 206 if (entryIndex.Found) 207 { 208 if ((requests & RequestFlags.RawEntry) != 0) 209 { 210 entry = _effectiveValues[entryIndex.Index]; 211 } 212 else 213 { 214 entry = GetEffectiveValue( 215 entryIndex, 216 dp, 217 requests); 218 } 219 } 220 else 221 { 222 entry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Unknown); 223 } 224 225 if (entry.Value == DependencyProperty.UnsetValue) 226 { 227 if (dp.IsPotentiallyInherited) 228 { 229 if (metadata == null) 230 { 231 metadata = dp.GetMetadata(DependencyObjectType); 232 } 233 234 if (metadata.IsInherited) 235 { 236 DependencyObject inheritanceParent = InheritanceParent; 237 if (inheritanceParent != null) 238 { 239 entryIndex = inheritanceParent.LookupEntry(dp.GlobalIndex); 240 241 if (entryIndex.Found) 242 { 243 entry = inheritanceParent.GetEffectiveValue( 244 entryIndex, 245 dp, 246 requests & RequestFlags.DeferredReferences); 247 entry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited; 248 } 249 } 250 } 251 252 if (entry.Value != DependencyProperty.UnsetValue) 253 { 254 return entry; 255 } 256 } 257 258 if ((requests & RequestFlags.SkipDefault) == 0) 259 { 260 if (dp.IsPotentiallyUsingDefaultValueFactory) 261 { 262 if (metadata == null) 263 { 264 metadata = dp.GetMetadata(DependencyObjectType); 265 } 266 267 if (((requests & (RequestFlags.DeferredReferences | RequestFlags.RawEntry)) != 0) && metadata.UsingDefaultValueFactory) 268 { 269 entry.BaseValueSourceInternal = BaseValueSourceInternal.Default; 270 271 entry.Value = new DeferredMutableDefaultReference(metadata, this, dp); 272 return entry; 273 } 274 } 275 else if (!dp.IsDefaultValueChanged) 276 { 277 return EffectiveValueEntry.CreateDefaultValueEntry(dp, dp.DefaultMetadata.DefaultValue); 278 } 279 280 if (metadata == null) 281 { 282 metadata = dp.GetMetadata(DependencyObjectType); 283 } 284 285 return EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 286 } 287 } 288 return entry; 289 } 290 291 /// <summary> 292 /// This overload of GetValue assumes that entryIndex is valid. 293 /// It also does not do the check storage on the InheritanceParent. 294 /// </summary> 295 private EffectiveValueEntry GetEffectiveValue( 296 EntryIndex entryIndex, 297 DependencyProperty dp, 298 RequestFlags requests) 299 { 300 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 301 EffectiveValueEntry effectiveEntry = entry.GetFlattenedEntry(requests); 302 303 if (((requests & (RequestFlags.DeferredReferences | RequestFlags.RawEntry)) != 0) || !effectiveEntry.IsDeferredReference) 304 { 305 return effectiveEntry; 306 } 307 308 if (!entry.HasModifiers) 309 { 310 // For thread-safety, sealed DOs can't modify _effectiveValues. 311 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 312 313 if (!entry.HasExpressionMarker) 314 { 315 // The value for this property was meant to come from a dictionary 316 // and the creation of that value had been deferred until this 317 // time for better performance. Now is the time to actually instantiate 318 // this value by querying it from the dictionary. Once we have the 319 // value we can actually replace the deferred reference marker 320 // with the actual value. 321 DeferredReference reference = (DeferredReference)entry.Value; 322 object value = reference.GetValue(entry.BaseValueSourceInternal); 323 324 if (!dp.IsValidValue(value)) 325 { 326 throw new InvalidOperationException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 327 } 328 329 // Make sure the entryIndex is in sync after 330 // the inflation of the deferred reference. 331 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 332 333 entry.Value = value; 334 335 _effectiveValues[entryIndex.Index] = entry; 336 return entry; 337 } 338 } 339 else 340 { 341 // The value for this property was meant to come from a dictionary 342 // and the creation of that value had been deferred until this 343 // time for better performance. Now is the time to actually instantiate 344 // this value by querying it from the dictionary. Once we have the 345 // value we can actually replace the deferred reference marker 346 // with the actual value. 347 348 ModifiedValue modifiedValue = entry.ModifiedValue; 349 DeferredReference reference = null; 350 bool referenceFromExpression = false; 351 352 if (entry.IsCoercedWithCurrentValue) 353 { 354 if (!entry.IsAnimated) 355 { 356 reference = modifiedValue.CoercedValue as DeferredReference; 357 } 358 } 359 360 if (reference == null && entry.IsExpression) 361 { 362 if (!entry.IsAnimated && !entry.IsCoerced) 363 { 364 reference = (DeferredReference) modifiedValue.ExpressionValue; 365 referenceFromExpression = true; 366 } 367 } 368 369 Debug.Assert(reference != null, "the only modified values that can have deferredreferences are (a) expression, (b) coerced control value"); 370 if (reference == null) 371 { 372 return effectiveEntry; 373 } 374 375 object value = reference.GetValue(entry.BaseValueSourceInternal); 376 377 if (!dp.IsValidValue(value)) 378 { 379 throw new InvalidOperationException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 380 } 381 382 // Make sure the entryIndex is in sync after 383 // the inflation of the deferred reference. 384 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 385 386 if (referenceFromExpression) 387 { 388 entry.SetExpressionValue(value, modifiedValue.BaseValue); 389 } 390 else 391 { 392 entry.SetCoercedValue(value, null, true /* skipBaseValueChecks */, entry.IsCoercedWithCurrentValue); 393 } 394 395 _effectiveValues[entryIndex.Index] = entry; 396 397 effectiveEntry.Value = value; 398 } 399 return effectiveEntry; 400 } 401 402 /// <summary> 403 /// Sets the local value of a property 404 /// </summary> 405 /// <param name="dp">Dependency property</param> 406 /// <param name="value">New local value</param> 407 public void SetValue(DependencyProperty dp, object value) 408 { 409 // Do not allow foreign threads access. 410 // (This is a noop if this object is not assigned to a Dispatcher.) 411 // 412 this.VerifyAccess(); 413 414 // Cache the metadata object this method needed to get anyway. 415 PropertyMetadata metadata = SetupPropertyChange(dp); 416 417 // Do standard property set 418 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, false /* coerceWithCurrentValue */, OperationType.Unknown, false /* isInternal */); 419 } 420 421 /// <summary> 422 /// Sets the value of a property without changing its value source. 423 /// </summary> 424 /// <param name="dp">Dependency property</param> 425 /// <param name="value">New value</param> 426 /// <remarks> 427 /// This method is intended for use by a component that wants to 428 /// programmatically set the value of one of its own properties, in a 429 /// way that does not disable an application's declared use of that property. 430 /// SetCurrentValue changes the effective value of the property, but 431 /// existing triggers, data-binding, styles, etc. will continue to 432 /// work. 433 /// </remarks> 434 public void SetCurrentValue(DependencyProperty dp, object value) 435 { 436 // Do not allow foreign threads access. 437 // (This is a noop if this object is not assigned to a Dispatcher.) 438 this.VerifyAccess(); 439 440 // Cache the metadata object this method needed to get anyway. 441 PropertyMetadata metadata = SetupPropertyChange(dp); 442 443 // Do standard property set 444 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, true /* coerceWithCurrentValue */, OperationType.Unknown, false /* isInternal */); 445 } 446 447 /// <summary> 448 /// Sets the local value of a property 449 /// The purpose of this internal method is to reuse BooleanBoxes when setting boolean value 450 /// </summary> 451 /// <param name="dp">Dependency property</param> 452 /// <param name="value">New local value</param> 453 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 454 internal void SetValue(DependencyProperty dp, bool value) 455 { 456 SetValue(dp, MS.Internal.KnownBoxes.BooleanBoxes.Box(value)); 457 } 458 459 /// <summary> 460 /// Sets the current value of a property 461 /// The purpose of this internal method is to reuse BooleanBoxes when setting boolean value 462 /// </summary> 463 /// <param name="dp">Dependency property</param> 464 /// <param name="value">New local value</param> 465 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 466 internal void SetCurrentValue(DependencyProperty dp, bool value) 467 { 468 SetCurrentValue(dp, MS.Internal.KnownBoxes.BooleanBoxes.Box(value)); 469 } 470 471 /// <summary> 472 /// Internal version of SetValue that bypasses type check in IsValidValue; 473 /// This is used in property setters 474 /// </summary> 475 /// <param name="dp">Dependency property</param> 476 /// <param name="value">New local value</param> 477 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 478 internal void SetValueInternal(DependencyProperty dp, object value) 479 { 480 // Do not allow foreign threads access. 481 // (This is a noop if this object is not assigned to a Dispatcher.) 482 // 483 this.VerifyAccess(); 484 485 // Cache the metadata object this method needed to get anyway. 486 PropertyMetadata metadata = SetupPropertyChange(dp); 487 488 // Do standard property set 489 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, false /* coerceWithCurrentValue */, OperationType.Unknown, true /* isInternal */); 490 } 491 492 /// <summary> 493 /// Internal version of SetCurrentValue that bypasses type check in IsValidValue; 494 /// This is used in property setters 495 /// </summary> 496 /// <param name="dp">Dependency property</param> 497 /// <param name="value">New local value</param> 498 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 499 internal void SetCurrentValueInternal(DependencyProperty dp, object value) 500 { 501 // Do not allow foreign threads access. 502 // (This is a noop if this object is not assigned to a Dispatcher.) 503 // 504 this.VerifyAccess(); 505 506 // Cache the metadata object this method needed to get anyway. 507 PropertyMetadata metadata = SetupPropertyChange(dp); 508 509 // Do standard property set 510 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, true /* coerceWithCurrentValue */, OperationType.Unknown, true /* isInternal */); 511 } 512 513 /// <summary> 514 /// Sets the local value of a property. 515 /// </summary> 516 [FriendAccessAllowed] // Built into Base, also used by Framework. 517 internal void SetDeferredValue(DependencyProperty dp, DeferredReference deferredReference) 518 { 519 // Cache the metadata object this method needed to get anyway. 520 PropertyMetadata metadata = SetupPropertyChange(dp); 521 522 // Do standard property set 523 SetValueCommon(dp, deferredReference, metadata, true /* coerceWithDeferredReference */, false /* coerceWithCurrentValue */, OperationType.Unknown, false /* isInternal */); 524 } 525 526 /// <summary> 527 /// Sets the value of a property to a deferred reference, without changing the ValueSource. 528 /// </summary> 529 [FriendAccessAllowed] // Built into Base, also used by Framework. 530 internal void SetCurrentDeferredValue(DependencyProperty dp, DeferredReference deferredReference) 531 { 532 // Cache the metadata object this method needed to get anyway. 533 PropertyMetadata metadata = SetupPropertyChange(dp); 534 535 // Do standard property set 536 SetValueCommon(dp, deferredReference, metadata, true /* coerceWithDeferredReference */, true /* coerceWithCurrentValue */, OperationType.Unknown, false /* isInternal */); 537 } 538 539 /// <summary> 540 /// Sets the local value of a property with a mutable default value. 541 /// </summary> 542 [FriendAccessAllowed] // Built into Base, also used by Framework. 543 internal void SetMutableDefaultValue(DependencyProperty dp, object value) 544 { 545 // Cache the metadata object this method needed to get anyway. 546 PropertyMetadata metadata = SetupPropertyChange(dp); 547 548 // Do standard property set 549 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, false /* coerceWithCurrentValue */, OperationType.ChangeMutableDefaultValue, false /* isInternal */); 550 } 551 552 /// <summary> 553 /// Sets the local value of a property 554 /// The purpose of this internal method is to reuse BooleanBoxes when setting boolean value 555 /// </summary> 556 /// <param name="dp">Dependency property key</param> 557 /// <param name="value">New local value</param> 558 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 559 internal void SetValue(DependencyPropertyKey dp, bool value) 560 { 561 SetValue(dp, MS.Internal.KnownBoxes.BooleanBoxes.Box(value)); 562 } 563 564 /// <summary> 565 /// Sets the local value of a property 566 /// </summary> 567 public void SetValue(DependencyPropertyKey key, object value) 568 { 569 // Do not allow foreign threads access. 570 // (This is a noop if this object is not assigned to a Dispatcher.) 571 // 572 this.VerifyAccess(); 573 574 DependencyProperty dp; 575 576 // Cache the metadata object this method needed to get anyway. 577 PropertyMetadata metadata = SetupPropertyChange(key, out dp); 578 579 // Do standard property set 580 SetValueCommon(dp, value, metadata, false /* coerceWithDeferredReference */, false /* coerceWithCurrentValue */, OperationType.Unknown, false /* isInternal */); 581 } 582 583 /// <summary> 584 /// Called by SetValue or ClearValue to verify that the property 585 /// can be changed. 586 /// </summary> 587 private PropertyMetadata SetupPropertyChange(DependencyProperty dp) 588 { 589 if ( dp != null ) 590 { 591 if ( !dp.ReadOnly ) 592 { 593 // Get type-specific metadata for this property 594 return dp.GetMetadata(DependencyObjectType); 595 } 596 else 597 { 598 throw new InvalidOperationException(SR.Get(SRID.ReadOnlyChangeNotAllowed, dp.Name)); 599 } 600 } 601 else 602 { 603 throw new ArgumentNullException("dp"); 604 } 605 } 606 607 /// <summary> 608 /// Called by SetValue or ClearValue to verify that the property 609 /// can be changed. 610 /// </summary> 611 private PropertyMetadata SetupPropertyChange(DependencyPropertyKey key, out DependencyProperty dp) 612 { 613 if ( key != null ) 614 { 615 dp = key.DependencyProperty; 616 Debug.Assert(dp != null); 617 618 dp.VerifyReadOnlyKey(key); 619 620 // Get type-specific metadata for this property 621 return dp.GetMetadata(DependencyObjectType); 622 } 623 else 624 { 625 throw new ArgumentNullException("key"); 626 } 627 } 628 629 /// <summary> 630 /// The common code shared by all variants of SetValue 631 /// </summary> 632 // Takes metadata from caller because most of them have already retrieved it 633 // for their own purposes, avoiding the duplicate GetMetadata call. 634 private void SetValueCommon( 635 DependencyProperty dp, 636 object value, 637 PropertyMetadata metadata, 638 bool coerceWithDeferredReference, 639 bool coerceWithCurrentValue, 640 OperationType operationType, 641 bool isInternal) 642 { 643 if (IsSealed) 644 { 645 throw new InvalidOperationException(SR.Get(SRID.SetOnReadOnlyObjectNotAllowed, this)); 646 } 647 648 Expression newExpr = null; 649 DependencySource[] newSources = null; 650 651 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 652 653 // Treat Unset as a Clear 654 if( value == DependencyProperty.UnsetValue ) 655 { 656 Debug.Assert(!coerceWithCurrentValue, "Don't call SetCurrentValue with UnsetValue"); 657 // Parameters should have already been validated, so we call 658 // into the private method to avoid validating again. 659 ClearValueCommon(entryIndex, dp, metadata); 660 return; 661 } 662 663 // Validate the "value" against the DP. 664 bool isDeferredReference = false; 665 bool newValueHasExpressionMarker = (value == ExpressionInAlternativeStore); 666 667 // First try to validate the value; only after this validation fails should we 668 // do the more expensive checks (type checks) for the less common scenarios 669 if (!newValueHasExpressionMarker) 670 { 671 bool isValidValue = isInternal ? dp.IsValidValueInternal(value) : dp.IsValidValue(value); 672 673 // for properties of type "object", we have to always check for expression & deferredreference 674 if (!isValidValue || dp.IsObjectType) 675 { 676 // 2nd most common is expression 677 newExpr = value as Expression; 678 if (newExpr != null) 679 { 680 // For Expressions, perform additional validation 681 // Make sure Expression is "attachable" 682 if (!newExpr.Attachable) 683 { 684 throw new ArgumentException(SR.Get(SRID.SharingNonSharableExpression)); 685 } 686 687 // Check dispatchers of all Sources 688 // CALLBACK 689 newSources = newExpr.GetSources(); 690 ValidateSources(this, newSources, newExpr); 691 } 692 else 693 { 694 // and least common is DeferredReference 695 isDeferredReference = (value is DeferredReference); 696 if (!isDeferredReference) 697 { 698 if (!isValidValue) 699 { 700 // it's not a valid value & it's not an expression, so throw 701 throw new ArgumentException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 702 } 703 } 704 } 705 } 706 } 707 708 // Get old value 709 EffectiveValueEntry oldEntry; 710 if (operationType == OperationType.ChangeMutableDefaultValue) 711 { 712 oldEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Default); 713 oldEntry.Value = value; 714 } 715 else 716 { 717 oldEntry = GetValueEntry(entryIndex, dp, metadata, RequestFlags.RawEntry); 718 } 719 720 // if there's an expression in some other store, fetch it now 721 Expression currentExpr = 722 (oldEntry.HasExpressionMarker) ? _getExpressionCore(this, dp, metadata) 723 : (oldEntry.IsExpression) ? (oldEntry.LocalValue as Expression) 724 : null; 725 726 // Allow expression to store value if new value is 727 // not an Expression, if applicable 728 729 bool handled = false; 730 if ((currentExpr != null) && (newExpr == null)) 731 { 732 // Resolve deferred references because we haven't modified 733 // the expression code to work with DeferredReference yet. 734 if (isDeferredReference) 735 { 736 value = ((DeferredReference) value).GetValue(BaseValueSourceInternal.Local); 737 } 738 739 // CALLBACK 740 handled = currentExpr.SetValue(this, dp, value); 741 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 742 } 743 744 // Create the new effective value entry 745 EffectiveValueEntry newEntry; 746 if (handled) 747 { 748 // If expression handled set, then done 749 if (entryIndex.Found) 750 { 751 newEntry = _effectiveValues[entryIndex.Index]; 752 } 753 else 754 { 755 // the expression.SetValue resulted in this value being removed from the table; 756 // use the default value. 757 newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 758 } 759 760 coerceWithCurrentValue = false; // expression already handled the control-value 761 } 762 else 763 { 764 // allow a control-value to coerce an expression value, when the 765 // expression didn't handle the value 766 if (coerceWithCurrentValue && currentExpr != null) 767 { 768 currentExpr = null; 769 } 770 771 newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Local); 772 773 // detach the old expression, if applicable 774 if (currentExpr != null) 775 { 776 // CALLBACK 777 DependencySource[] currentSources = currentExpr.GetSources(); 778 779 UpdateSourceDependentLists(this, dp, currentSources, currentExpr, false); // Remove 780 781 // CALLBACK 782 currentExpr.OnDetach(this, dp); 783 currentExpr.MarkDetached(); 784 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 785 } 786 787 // attach the new expression, if applicable 788 if (newExpr == null) 789 { 790 // simple local value set 791 newEntry.HasExpressionMarker = newValueHasExpressionMarker; 792 newEntry.Value = value; 793 } 794 else 795 { 796 Debug.Assert(!coerceWithCurrentValue, "Expression values not supported in SetCurrentValue"); 797 798 // First put the expression in the effectivevalueentry table for this object; 799 // this allows the expression to update the value accordingly in OnAttach 800 SetEffectiveValue(entryIndex, dp, dp.GlobalIndex, metadata, newExpr, BaseValueSourceInternal.Local); 801 802 // Before the expression is attached it has default value 803 object defaultValue = metadata.GetDefaultValue(this, dp); 804 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 805 SetExpressionValue(entryIndex, defaultValue, newExpr); 806 UpdateSourceDependentLists(this, dp, newSources, newExpr, true); // Add 807 808 newExpr.MarkAttached(); 809 810 // CALLBACK 811 newExpr.OnAttach(this, dp); 812 813 // the attach may have added entries in the effective value table ... 814 // so, update the entryIndex accordingly. 815 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 816 817 newEntry = EvaluateExpression( 818 entryIndex, 819 dp, 820 newExpr, 821 metadata, 822 oldEntry, 823 _effectiveValues[entryIndex.Index]); 824 825 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 826 } 827 } 828 829 UpdateEffectiveValue( 830 entryIndex, 831 dp, 832 metadata, 833 oldEntry, 834 ref newEntry, 835 coerceWithDeferredReference, 836 coerceWithCurrentValue, 837 operationType); 838 } 839 840 // 841 // This is a helper routine to set this DO as the inheritance context of another, 842 // which has been set as a DP value here. 843 // 844 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 845 internal bool ProvideSelfAsInheritanceContext( object value, DependencyProperty dp ) 846 { 847 DependencyObject doValue = value as DependencyObject; 848 if (doValue != null) 849 { 850 return ProvideSelfAsInheritanceContext(doValue, dp); 851 } 852 else 853 { 854 return false; 855 } 856 } 857 858 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 859 internal bool ProvideSelfAsInheritanceContext( DependencyObject doValue, DependencyProperty dp ) 860 { 861 // We have to call Freezable.AddInheritanceContext even if the request 862 // for a new InheritanceContext is not allowed, because Freezable depends 863 // on side-effects from setting the "Freezable context". Freezable's 864 // implementation does its own checks of the conditions omitted here. 865 // 866 867 868 if (doValue != null && 869 this.ShouldProvideInheritanceContext(doValue, dp) && 870 (doValue is Freezable || 871 (this.CanBeInheritanceContext && 872 !doValue.IsInheritanceContextSealed) 873 )) 874 { 875 DependencyObject oldInheritanceContext = doValue.InheritanceContext; 876 doValue.AddInheritanceContext(this, dp); 877 878 // return true if the inheritance context actually changed to the new value 879 return (this == doValue.InheritanceContext && this != oldInheritanceContext); 880 } 881 else 882 { 883 return false; 884 } 885 } 886 887 // 888 // This is a helper routine to remove this DO as the inheritance context of another. 889 // 890 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 891 internal bool RemoveSelfAsInheritanceContext( object value, DependencyProperty dp ) 892 { 893 DependencyObject doValue = value as DependencyObject; 894 if (doValue != null) 895 { 896 return RemoveSelfAsInheritanceContext(doValue, dp); 897 } 898 else 899 { 900 return false; 901 } 902 } 903 904 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 905 internal bool RemoveSelfAsInheritanceContext( DependencyObject doValue, DependencyProperty dp ) 906 { 907 // We have to call Freezable.RemoveInheritanceContext even if the request 908 // for a new InheritanceContext is not allowed, because Freezable depends 909 // on side-effects from setting the "Freezable context". Freezable's 910 // implementation does its own checks of the conditions omitted here. 911 // 912 913 914 if (doValue != null && 915 this.ShouldProvideInheritanceContext(doValue, dp) && 916 (doValue is Freezable || 917 (this.CanBeInheritanceContext && 918 !doValue.IsInheritanceContextSealed) 919 )) 920 { 921 DependencyObject oldInheritanceContext = doValue.InheritanceContext; 922 doValue.RemoveInheritanceContext(this, dp); 923 924 // return true if the inheritance context actually changed to the new value 925 return (this == oldInheritanceContext && doValue.InheritanceContext != oldInheritanceContext); 926 } 927 else 928 { 929 return false; 930 } 931 } 932 933 934 /// <summary> 935 /// Clears the local value of a property 936 /// </summary> 937 /// <param name="dp">Dependency property</param> 938 public void ClearValue(DependencyProperty dp) 939 { 940 // Do not allow foreign threads to clear properties. 941 // (This is a noop if this object is not assigned to a Dispatcher.) 942 // 943 this.VerifyAccess(); 944 945 // Cache the metadata object this method needed to get anyway. 946 PropertyMetadata metadata = SetupPropertyChange(dp); 947 948 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 949 950 ClearValueCommon(entryIndex, dp, metadata); 951 } 952 953 /// <summary> 954 /// Clears the local value of a property 955 /// </summary> 956 public void ClearValue(DependencyPropertyKey key) 957 { 958 // Do not allow foreign threads to clear properties. 959 // (This is a noop if this object is not assigned to a Dispatcher.) 960 // 961 this.VerifyAccess(); 962 963 DependencyProperty dp; 964 965 // Cache the metadata object this method needed to get anyway. 966 PropertyMetadata metadata = SetupPropertyChange(key, out dp); 967 968 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 969 970 ClearValueCommon(entryIndex, dp, metadata); 971 } 972 973 /// <summary> 974 /// The common code shared by all variants of ClearValue 975 /// </summary> 976 private void ClearValueCommon(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata) 977 { 978 if (IsSealed) 979 { 980 throw new InvalidOperationException(SR.Get(SRID.ClearOnReadOnlyObjectNotAllowed, this)); 981 } 982 983 // Get old value 984 EffectiveValueEntry oldEntry = GetValueEntry( 985 entryIndex, 986 dp, 987 metadata, 988 RequestFlags.RawEntry); 989 990 // Get current local value 991 // (No need to go through read local callback, just checking 992 // for presence of Expression) 993 object current = oldEntry.LocalValue; 994 995 // Get current expression 996 Expression currentExpr = (oldEntry.IsExpression) ? (current as Expression) : null; 997 998 // Inform value expression of detachment, if applicable 999 if (currentExpr != null) 1000 { 1001 // CALLBACK 1002 DependencySource[] currentSources = currentExpr.GetSources(); 1003 1004 UpdateSourceDependentLists(this, dp, currentSources, currentExpr, false); // Remove 1005 1006 // CALLBACK 1007 currentExpr.OnDetach(this, dp); 1008 currentExpr.MarkDetached(); 1009 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 1010 } 1011 1012 // valuesource == Local && value == UnsetValue indicates that we are clearing the local value 1013 EffectiveValueEntry newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Local); 1014 1015 // Property is now invalid 1016 UpdateEffectiveValue( 1017 entryIndex, 1018 dp, 1019 metadata, 1020 oldEntry, 1021 ref newEntry, 1022 false /* coerceWithDeferredReference */, 1023 false /* coerceWithCurrentValue */, 1024 OperationType.Unknown); 1025 } 1026 1027 /// <summary> 1028 /// This method is called by DependencyObjectPropertyDescriptor to determine 1029 /// if a value is set for a given DP. 1030 /// </summary> 1031 internal bool ContainsValue(DependencyProperty dp) 1032 { 1033 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 1034 1035 if (!entryIndex.Found) 1036 { 1037 return false; 1038 } 1039 1040 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 1041 object value = entry.IsCoercedWithCurrentValue ? entry.ModifiedValue.CoercedValue : entry.LocalValue; 1042 return !object.ReferenceEquals(value, DependencyProperty.UnsetValue); 1043 } 1044 1045 // 1046 // Changes the sources of an existing Expression 1047 // 1048 internal static void ChangeExpressionSources(Expression expr, DependencyObject d, DependencyProperty dp, DependencySource[] newSources) 1049 { 1050 if (!expr.ForwardsInvalidations) 1051 { 1052 // Get current local value (should be provided Expression) 1053 // (No need to go through read local callback, just checking 1054 // for presence of Expression) 1055 EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex); 1056 1057 if (!entryIndex.Found || (d._effectiveValues[entryIndex.Index].LocalValue != expr)) 1058 { 1059 throw new ArgumentException(SR.Get(SRID.SourceChangeExpressionMismatch)); 1060 } 1061 } 1062 1063 // Get current sources 1064 // CALLBACK 1065 DependencySource[] currentSources = expr.GetSources(); 1066 1067 // Remove old 1068 if (currentSources != null) 1069 { 1070 UpdateSourceDependentLists(d, dp, currentSources, expr, false); // Remove 1071 } 1072 1073 // Add new 1074 if (newSources != null) 1075 { 1076 UpdateSourceDependentLists(d, dp, newSources, expr, true); // Add 1077 } 1078 } 1079 1080 /// <summary> 1081 /// Coerce a property value 1082 /// </summary> 1083 /// <param name="dp">Dependency property</param> 1084 public void CoerceValue(DependencyProperty dp) 1085 { 1086 // Do not allow foreign threads access. 1087 // (This is a noop if this object is not assigned to a Dispatcher.) 1088 // 1089 this.VerifyAccess(); 1090 1091 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 1092 PropertyMetadata metadata = dp.GetMetadata(DependencyObjectType); 1093 1094 // if the property has a coerced-with-control value, apply the coercion 1095 // to that value. This is done by simply calling SetCurrentValue. 1096 if (entryIndex.Found) 1097 { 1098 EffectiveValueEntry entry = GetValueEntry(entryIndex, dp, metadata, RequestFlags.RawEntry); 1099 if (entry.IsCoercedWithCurrentValue) 1100 { 1101 SetCurrentValue(dp, entry.ModifiedValue.CoercedValue); 1102 return; 1103 } 1104 } 1105 1106 // IsCoerced == true && value == UnsetValue indicates that we need to re-coerce this value 1107 EffectiveValueEntry newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced); 1108 1109 UpdateEffectiveValue( 1110 entryIndex, 1111 dp, 1112 metadata, 1113 new EffectiveValueEntry() /* oldEntry */, 1114 ref newEntry, 1115 false /* coerceWithDeferredReference */, 1116 false /* coerceWithCurrentValue */, 1117 OperationType.Unknown); 1118 } 1119 1120 /// <summary> 1121 /// This is to enable some performance-motivated shortcuts in property 1122 /// invalidation. When this is called, it means the caller knows the 1123 /// value of the property is pointing to the same object instance as 1124 /// before, but the meaning has changed because something within that 1125 /// object has changed. 1126 /// </summary> 1127 /// <remarks> 1128 /// Clients who are unaware of this will still behave correctly, if not 1129 /// particularly performant, by assuming that we have a new instance. 1130 /// Since invalidation operations are synchronous, we can set a bit 1131 /// to maintain this knowledge through the invalidation operation. 1132 /// This would be problematic in cross-thread operations, but the only 1133 /// time DependencyObject can be used across thread in today's design 1134 /// is when it is a Freezable object that has been Frozen. Frozen 1135 /// means no more changes, which means no more invalidations. 1136 /// 1137 /// This is being done as an internal method to enable the performance 1138 /// bug #1114409. This is candidate for a public API but we can't 1139 /// do that kind of work at the moment. 1140 /// </remarks> 1141 [FriendAccessAllowed] // Built into Base, also used by Framework. 1142 internal void InvalidateSubProperty(DependencyProperty dp) 1143 { 1144 // when a sub property changes, send a Changed notification with old and new value being the same, and with 1145 // IsASubPropertyChange set to true 1146 NotifyPropertyChange(new DependencyPropertyChangedEventArgs(dp, dp.GetMetadata(DependencyObjectType), GetValue(dp))); 1147 } 1148 1149 /// <summary> 1150 /// Notify the current DependencyObject that a "sub-property" 1151 /// change has occurred on the given DependencyProperty. 1152 /// </summary> 1153 /// <remarks> 1154 /// This does the same work as InvalidateSubProperty, and in addition 1155 /// it raise the Freezable.Changed event if the current DependencyObject 1156 /// is a Freezable. This method should be called whenever an 1157 /// intermediate object is responsible for propagating the Freezable.Changed 1158 /// event (i.e. when the Freezable system doesn't propagate the event itself). 1159 /// </remarks> 1160 [FriendAccessAllowed] // Built into Base, also used by Framework. 1161 internal void NotifySubPropertyChange(DependencyProperty dp) 1162 { 1163 InvalidateSubProperty(dp); 1164 1165 // if the target is a Freezable, call FireChanged to kick off 1166 // notifications to the Freezable's parent chain. 1167 Freezable freezable = this as Freezable; 1168 if (freezable != null) 1169 { 1170 freezable.FireChanged(); 1171 } 1172 } 1173 1174 /// <summary> 1175 /// Invalidates a property 1176 /// </summary> 1177 /// <param name="dp">Dependency property</param> 1178 //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 1179 public void InvalidateProperty(DependencyProperty dp) 1180 { 1181 InvalidateProperty(dp, preserveCurrentValue:false); 1182 } 1183 1184 // Invalidation, optionally preserving the current value if the base 1185 // value doesn't change. 1186 // The flag is set only by triggers, as a workaround for a missing API. 1187 // When we added SetCurrentValue, we should have also added ClearCurrentValue 1188 // to give controls a way to remove the current value. Lacking that, controls use 1189 // InvalidateProperty (VirtualizingStackPanel does this), relying on behavior 1190 // that should also have been different - an invalidation that doesn't change 1191 // the base value should preserve the current value. 1192 // This matters for triggers (see Dev11 bug 72825). When any input to a 1193 // trigger condition changes, the trigger simply invalidates all the properties 1194 // mentioned in its setters. These invalidations often discover no value change - 1195 // (example: Trigger condition is "IsVisible && HasErrors"; if IsVisible is false, 1196 // changing input HasErrors won't change the condition value. The dependent 1197 // properties are invalidated, but they don't actually change value.) 1198 // To fix the bug, we are putting in the "preserve current value" behavior, but 1199 // only for invalidations that come from triggers. 1200 internal void InvalidateProperty(DependencyProperty dp, bool preserveCurrentValue) 1201 { 1202 // Do not allow foreign threads access. 1203 // (This is a noop if this object is not assigned to a Dispatcher.) 1204 // 1205 this.VerifyAccess(); 1206 1207 if (dp == null) 1208 { 1209 throw new ArgumentNullException("dp"); 1210 } 1211 1212 EffectiveValueEntry newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Unknown); 1213 newEntry.IsCoercedWithCurrentValue = preserveCurrentValue; 1214 1215 UpdateEffectiveValue( 1216 LookupEntry(dp.GlobalIndex), 1217 dp, 1218 dp.GetMetadata(DependencyObjectType), 1219 new EffectiveValueEntry() /* oldEntry */, 1220 ref newEntry, 1221 false /* coerceWithDeferredReference */, 1222 false /* coerceWithCurrentValue */, 1223 OperationType.Unknown); 1224 } 1225 1226 // 1227 // This method 1228 // 1. Re-evaluates the effective value for the given property and fires the property changed notification 1229 // 2. When this method is invoked with the coersion flag set to false it means that we will simply 1230 // coerce and will not try to re-evaluate the base value for the property 1231 // 1232 [FriendAccessAllowed] // Declared in Base also used in Framework 1233 internal UpdateResult UpdateEffectiveValue( 1234 EntryIndex entryIndex, 1235 DependencyProperty dp, 1236 PropertyMetadata metadata, 1237 EffectiveValueEntry oldEntry, 1238 ref EffectiveValueEntry newEntry, 1239 bool coerceWithDeferredReference, 1240 bool coerceWithCurrentValue, 1241 OperationType operationType) 1242 { 1243 if (dp == null) 1244 { 1245 throw new ArgumentNullException("dp"); 1246 } 1247 1248 #region EventTracing 1249 #if VERBOSE_PROPERTY_EVENT 1250 bool isDynamicTracing = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose); // This was under "normal" 1251 if (isDynamicTracing) 1252 { 1253 ++InvalidationCount; 1254 if( InvalidationCount % 100 == 0 ) 1255 { 1256 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, 1257 MS.Utility.EventType.Info, 1258 InvalidationCount ); 1259 } 1260 1261 string TypeAndName = String.Format(CultureInfo.InvariantCulture, "[{0}]{1}({2})",GetType().Name,dp.Name,base.GetHashCode()); // FxCop wanted the CultureInfo.InvariantCulture 1262 1263 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, 1264 MS.Utility.EventType.StartEvent, 1265 base.GetHashCode(), TypeAndName); // base.GetHashCode() to avoid calling a virtual, which FxCop doesn't like. 1266 } 1267 #endif 1268 1269 1270 #endregion EventTracing 1271 1272 #if NESTED_OPERATIONS_CHECK 1273 // Are we invalidating out of control? 1274 if( NestedOperations > NestedOperationMaximum ) 1275 { 1276 // We're invalidating out of control, time to abort. 1277 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."); 1278 } 1279 NestedOperations++; // Decrement in the finally block 1280 #endif 1281 int targetIndex = dp.GlobalIndex; 1282 1283 if (oldEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown) 1284 { 1285 // Do a full get value of the old entry if it isn't supplied. 1286 // It isn't supplied in cases where we are *unsetting* a value 1287 // (e.g. ClearValue, style unapply, trigger unapply) 1288 oldEntry = GetValueEntry( 1289 entryIndex, 1290 dp, 1291 metadata, 1292 RequestFlags.RawEntry); 1293 } 1294 1295 object oldValue = oldEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 1296 1297 1298 /* 1299 if( TraceDependencyProperty.IsEnabled ) 1300 { 1301 TraceDependencyProperty.Trace( 1302 TraceEventType.Verbose, 1303 TraceDependencyProperty.UpdateEffectiveValueStart, 1304 this, 1305 dp, 1306 dp.OwnerType, 1307 oldValue, 1308 oldEntry.BaseValueSourceInternal ); 1309 } 1310 */ 1311 1312 // for control-value coercion, extract the desired control value, then 1313 // reset the new entry to ask for a re-evaluation with coercion 1314 object controlValue = null; 1315 if (coerceWithCurrentValue) 1316 { 1317 controlValue = newEntry.Value; 1318 newEntry = new EffectiveValueEntry(dp, FullValueSource.IsCoerced); 1319 } 1320 1321 // check for early-out opportunities: 1322 // 1) the new entry is of lower priority than the current entry 1323 if ((newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Unknown) && 1324 (newEntry.BaseValueSourceInternal < oldEntry.BaseValueSourceInternal)) 1325 { 1326 return 0; 1327 } 1328 1329 bool isReEvaluate = false; 1330 bool isCoerceValue = false; 1331 bool isClearValue = false; 1332 1333 if (newEntry.Value == DependencyProperty.UnsetValue) 1334 { 1335 FullValueSource fullValueSource = newEntry.FullValueSource; 1336 isCoerceValue = (fullValueSource == FullValueSource.IsCoerced); 1337 isReEvaluate = true; 1338 1339 if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Local) 1340 { 1341 isClearValue = true; 1342 } 1343 } 1344 1345 // if we're not in an animation update (caused by AnimationStorage.OnCurrentTimeInvalidated) 1346 // then always force a re-evaluation if (a) there was an animation in play or (b) there's 1347 // an expression evaluation to be made 1348 if (isReEvaluate || 1349 (!newEntry.IsAnimated && 1350 (oldEntry.IsAnimated || 1351 (oldEntry.IsExpression && newEntry.IsExpression && (newEntry.ModifiedValue.BaseValue == oldEntry.ModifiedValue.BaseValue))))) 1352 { 1353 // we have to compute the new value 1354 if (!isCoerceValue) 1355 { 1356 newEntry = EvaluateEffectiveValue(entryIndex, dp, metadata, oldEntry, newEntry, operationType); 1357 1358 // Make sure that the call out did not cause a change to entryIndex 1359 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1360 1361 bool found = (newEntry.Value != DependencyProperty.UnsetValue); 1362 if (!found && metadata.IsInherited) 1363 { 1364 DependencyObject inheritanceParent = InheritanceParent; 1365 if (inheritanceParent != null) 1366 { 1367 // Fetch the IsDeferredValue flag from the InheritanceParent 1368 EntryIndex parentEntryIndex = inheritanceParent.LookupEntry(dp.GlobalIndex); 1369 if (parentEntryIndex.Found) 1370 { 1371 found = true; 1372 newEntry = inheritanceParent._effectiveValues[parentEntryIndex.Index].GetFlattenedEntry(RequestFlags.FullyResolved); 1373 newEntry.BaseValueSourceInternal = BaseValueSourceInternal.Inherited; 1374 } 1375 } 1376 } 1377 1378 // interesting that I just had to add this ... suggests that we are now overinvalidating 1379 if (!found) 1380 { 1381 newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 1382 } 1383 } 1384 else 1385 { 1386 if (!oldEntry.HasModifiers) 1387 { 1388 newEntry = oldEntry; 1389 } 1390 else 1391 { 1392 newEntry = new EffectiveValueEntry(dp, oldEntry.BaseValueSourceInternal); 1393 ModifiedValue modifiedValue = oldEntry.ModifiedValue; 1394 object baseValue = modifiedValue.BaseValue; 1395 newEntry.Value = baseValue; 1396 newEntry.HasExpressionMarker = oldEntry.HasExpressionMarker; 1397 1398 if (oldEntry.IsExpression) 1399 { 1400 newEntry.SetExpressionValue(modifiedValue.ExpressionValue, baseValue); 1401 } 1402 1403 if (oldEntry.IsAnimated) 1404 { 1405 newEntry.SetAnimatedValue(modifiedValue.AnimatedValue, baseValue); 1406 } 1407 } 1408 } 1409 } 1410 1411 // Coerce to current value 1412 if (coerceWithCurrentValue) 1413 { 1414 object baseValue = newEntry.GetFlattenedEntry(RequestFlags.CoercionBaseValue).Value; 1415 1416 ProcessCoerceValue( 1417 dp, 1418 metadata, 1419 ref entryIndex, 1420 ref targetIndex, 1421 ref newEntry, 1422 ref oldEntry, 1423 ref oldValue, 1424 baseValue, 1425 controlValue, 1426 null /*coerceValueCallback */, 1427 coerceWithDeferredReference, 1428 coerceWithCurrentValue, 1429 false /*skipBaseValueChecks*/); 1430 1431 // Make sure that the call out did not cause a change to entryIndex 1432 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1433 } 1434 1435 // Coerce Value 1436 if (metadata.CoerceValueCallback != null && 1437 !(isClearValue && newEntry.FullValueSource == (FullValueSource)BaseValueSourceInternal.Default)) 1438 { 1439 // CALLBACK 1440 object baseValue = newEntry.GetFlattenedEntry(RequestFlags.CoercionBaseValue).Value; 1441 1442 ProcessCoerceValue( 1443 dp, 1444 metadata, 1445 ref entryIndex, 1446 ref targetIndex, 1447 ref newEntry, 1448 ref oldEntry, 1449 ref oldValue, 1450 baseValue, 1451 null /* controlValue */, 1452 metadata.CoerceValueCallback, 1453 coerceWithDeferredReference, 1454 false /* coerceWithCurrentValue */, 1455 false /*skipBaseValueChecks*/); 1456 1457 // Make sure that the call out did not cause a change to entryIndex 1458 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1459 } 1460 1461 // The main difference between this callback and the metadata.CoerceValueCallback is that 1462 // designers want to be able to coerce during all value changes including a change to the 1463 // default value. Whereas metadata.CoerceValueCallback coerces all property values but the 1464 // default, because default values are meant to fit automatically fit into the coersion constraint. 1465 1466 if (dp.DesignerCoerceValueCallback != null) 1467 { 1468 // During a DesignerCoerceValueCallback the value obtained is stored in the same 1469 // member as the metadata.CoerceValueCallback. In this case we do not store the 1470 // baseValue in the entry. Thus the baseValue checks will the violated. That is the 1471 // reason for skipping these checks in this one case. 1472 1473 // Also before invoking the DesignerCoerceValueCallback the baseValue must 1474 // always be expanded if it is a DeferredReference 1475 1476 ProcessCoerceValue( 1477 dp, 1478 metadata, 1479 ref entryIndex, 1480 ref targetIndex, 1481 ref newEntry, 1482 ref oldEntry, 1483 ref oldValue, 1484 newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value, 1485 null /*controlValue*/, 1486 dp.DesignerCoerceValueCallback, 1487 false /*coerceWithDeferredReference*/, 1488 false /*coerceWithCurrentValue*/, 1489 true /*skipBaseValueChecks*/); 1490 1491 // Make sure that the call out did not cause a change to entryIndex 1492 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1493 } 1494 1495 UpdateResult result = 0; 1496 1497 if (newEntry.FullValueSource != (FullValueSource) BaseValueSourceInternal.Default) 1498 { 1499 Debug.Assert(newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Unknown, "Value source should be known at this point"); 1500 bool unsetValue = false; 1501 1502 if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Inherited) 1503 { 1504 if (DependencyObject.IsTreeWalkOperation(operationType) && 1505 (newEntry.IsCoerced || newEntry.IsAnimated)) 1506 { 1507 // an inherited value has been coerced or animated. This 1508 // should be treated as a new "set" of the property. 1509 // The current tree walk should not continue into the subtree, 1510 // but rather a new tree walk should start. 1511 1512 // this signals OnPropertyChanged to start a new tree walk 1513 // and mark the current node as SelfInheritanceParent 1514 operationType = OperationType.Unknown; 1515 1516 // this signals the caller not to continue the current 1517 // tree walk into the subtree 1518 result |= UpdateResult.InheritedValueOverridden; 1519 } 1520 else if (!IsSelfInheritanceParent) 1521 { 1522 // otherwise, just inherit the value from the InheritanceParent 1523 unsetValue = true; 1524 } 1525 } 1526 1527 if (unsetValue) 1528 { 1529 UnsetEffectiveValue(entryIndex, dp, metadata); 1530 } 1531 else 1532 { 1533 SetEffectiveValue(entryIndex, dp, metadata, newEntry, oldEntry); 1534 } 1535 } 1536 else 1537 { 1538 UnsetEffectiveValue(entryIndex, dp, metadata); 1539 } 1540 1541 // Change notifications are fired when the value actually changed or in 1542 // the case of the Freezable mutable factories when the value source changes. 1543 // Try AvaCop without the second condition to repro this problem. 1544 bool isAValueChange = !Equals(dp, oldValue, newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value); 1545 1546 if (isAValueChange) 1547 { 1548 result |= UpdateResult.ValueChanged; 1549 } 1550 1551 if (isAValueChange || 1552 (operationType == OperationType.ChangeMutableDefaultValue && oldEntry.BaseValueSourceInternal != newEntry.BaseValueSourceInternal) || 1553 (metadata.IsInherited && oldEntry.BaseValueSourceInternal != newEntry.BaseValueSourceInternal && operationType != OperationType.AddChild && operationType != OperationType.RemoveChild && operationType != OperationType.Inherit)) 1554 { 1555 result |= UpdateResult.NotificationSent; 1556 1557 try 1558 { 1559 // fire change notification 1560 NotifyPropertyChange( 1561 new DependencyPropertyChangedEventArgs( 1562 dp, 1563 metadata, 1564 isAValueChange, 1565 oldEntry, 1566 newEntry, 1567 operationType)); 1568 } 1569 finally 1570 { 1571 #if NESTED_OPERATIONS_CHECK 1572 NestedOperations--; 1573 #endif 1574 } 1575 } 1576 1577 #region EventTracing 1578 #if VERBOSE_PROPERTY_EVENT 1579 if (isDynamicTracing) 1580 { 1581 if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 1582 { 1583 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYINVALIDATIONGUID, MS.Utility.EventType.EndEvent); 1584 } 1585 } 1586 #endif 1587 #endregion EventTracing 1588 1589 1590 /* 1591 if( TraceDependencyProperty.IsEnabled ) 1592 { 1593 TraceDependencyProperty.Trace( 1594 TraceEventType.Verbose, 1595 TraceDependencyProperty.UpdateEffectiveValueStop, 1596 this, dp, dp.OwnerType, 1597 newEntry.Value, newEntry.BaseValueSourceInternal ); 1598 } 1599 */ 1600 1601 // There are two cases in which we need to adjust inheritance contexts: 1602 // 1603 // 1. The value pointed to this DP has changed, in which case 1604 // we need to move the context from the old value to the 1605 // new value. 1606 // 1607 // 2. The value has not changed, but the ValueSource for the 1608 // property has. (For example, we've gone from being a local 1609 // value to the result of a binding expression that just 1610 // happens to return the same DO instance.) In which case 1611 // we may need to add or remove contexts even though we 1612 // did not raise change notifications. 1613 // 1614 // We don't want to provide an inheritance context if the entry is 1615 // animated, coerced, is an expression, is coming from a style or 1616 // template, etc. To avoid this, we explicitly check that the 1617 // FullValueSource is Local. By checking FullValueSource rather than 1618 // BaseValueSource we are implicitly filtering out any sources which 1619 // have modifiers. (e.g., IsExpression, IsAnimated, etc.) 1620 1621 bool oldEntryHadContext = oldEntry.FullValueSource == (FullValueSource) BaseValueSourceInternal.Local; 1622 bool newEntryNeedsContext = newEntry.FullValueSource == (FullValueSource) BaseValueSourceInternal.Local; 1623 1624 // NOTE: We use result rather than isAValueChange below so that we 1625 // pick up mutable default promotion, etc. 1626 if (result != 0 || (oldEntryHadContext != newEntryNeedsContext)) 1627 { 1628 if (oldEntryHadContext) 1629 { 1630 // RemoveSelfAsInheritanceContext no-ops null, non-DO values, etc. 1631 RemoveSelfAsInheritanceContext(oldEntry.LocalValue, dp); 1632 } 1633 1634 // Become the context for the new value. This is happens after 1635 // invalidation so that FE has a chance to hookup the logical 1636 // tree first. This is done only if the current DependencyObject 1637 // wants to be in the InheritanceContext tree. 1638 if (newEntryNeedsContext) 1639 { 1640 // ProvideSelfAsInheritanceContext no-ops null, non-DO values, etc. 1641 ProvideSelfAsInheritanceContext(newEntry.LocalValue, dp); 1642 } 1643 1644 // DANGER: Callout might add/remove entries in the effective value table. 1645 // Uncomment the following if you need to use entryIndex post 1646 // context hookup. 1647 // 1648 // entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 1649 } 1650 1651 return result; 1652 } 1653 1654 private void ProcessCoerceValue( 1655 DependencyProperty dp, 1656 PropertyMetadata metadata, 1657 ref EntryIndex entryIndex, 1658 ref int targetIndex, 1659 ref EffectiveValueEntry newEntry, 1660 ref EffectiveValueEntry oldEntry, 1661 ref object oldValue, 1662 object baseValue, 1663 object controlValue, 1664 CoerceValueCallback coerceValueCallback, 1665 bool coerceWithDeferredReference, 1666 bool coerceWithCurrentValue, 1667 bool skipBaseValueChecks) 1668 { 1669 if (newEntry.IsDeferredReference) 1670 { 1671 Debug.Assert(!(newEntry.IsCoerced && !newEntry.IsCoercedWithCurrentValue) && 1672 !newEntry.IsAnimated, "Coerced or Animated value cannot be a deferred reference"); 1673 1674 // Allow values to stay deferred through coercion callbacks in 1675 // limited circumstances, when we know the listener is internal. 1676 // Since we never assign DeferredReference instances to 1677 // non-internal (non-friend assembly) classes, it's safe to skip 1678 // the dereference if the callback is to the DP owner (and not 1679 // a derived type). This is consistent with passing raw 1680 // DeferredReference instances to ValidateValue callbacks, which 1681 // only ever go to the owner class. 1682 if (!coerceWithDeferredReference || 1683 dp.OwnerType != metadata.CoerceValueCallback.Method.DeclaringType) // Need 2nd check to rule out derived class callback overrides. 1684 { 1685 // Resolve deferred references because we need the actual 1686 // baseValue to evaluate the correct animated value. This is done 1687 // by invoking GetValue for this property. 1688 DeferredReference dr = (DeferredReference) baseValue; 1689 baseValue = dr.GetValue(newEntry.BaseValueSourceInternal); 1690 1691 // Set the baseValue back into the entry 1692 newEntry.SetCoersionBaseValue(baseValue); 1693 1694 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1695 } 1696 } 1697 1698 object coercedValue = coerceWithCurrentValue ? controlValue : coerceValueCallback(this, baseValue); 1699 1700 // Make sure that the call out did not cause a change to entryIndex 1701 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1702 1703 // Even if we used the controlValue in the coerce callback, we still want to compare against the original baseValue 1704 // to determine if we need to set a coerced value. 1705 if (!Equals(dp, coercedValue, baseValue)) 1706 { 1707 // returning DependencyProperty.UnsetValue from a Coercion callback means "don't do the set" ... 1708 // or "use previous value" 1709 if (coercedValue == DependencyProperty.UnsetValue) 1710 { 1711 if (oldEntry.IsDeferredReference) 1712 { 1713 DeferredReference reference = (DeferredReference)oldValue; 1714 oldValue = reference.GetValue(oldEntry.BaseValueSourceInternal); 1715 1716 entryIndex = CheckEntryIndex(entryIndex, targetIndex); 1717 } 1718 1719 coercedValue = oldValue; 1720 } 1721 1722 // Note that we do not support the value being coerced to a 1723 // DeferredReference 1724 if (!dp.IsValidValue(coercedValue)) 1725 { 1726 // well... unless it's the control's "current value" 1727 if (!(coerceWithCurrentValue && coercedValue is DeferredReference)) 1728 throw new ArgumentException(SR.Get(SRID.InvalidPropertyValue, coercedValue, dp.Name)); 1729 } 1730 1731 // Set the coerced value here. All other values would 1732 // have been set during EvaluateEffectiveValue/GetValueCore. 1733 1734 newEntry.SetCoercedValue(coercedValue, baseValue, skipBaseValueChecks, coerceWithCurrentValue); 1735 } 1736 } 1737 1738 /// <summary> 1739 /// This is a helper method that is used to fire the property change notification through 1740 /// the callbacks and to all the dependents of this property such as bindings etc. 1741 /// </summary> 1742 [FriendAccessAllowed] // Built into Base, also used by Framework. 1743 internal void NotifyPropertyChange(DependencyPropertyChangedEventArgs args) 1744 { 1745 // fire change notification 1746 OnPropertyChanged(args); 1747 1748 if (args.IsAValueChange || args.IsASubPropertyChange) 1749 { 1750 // Invalidate all Dependents of this Source invalidation due 1751 // to Expression dependencies 1752 1753 DependencyProperty dp = args.Property; 1754 object objectDependentsListMap = DependentListMapField.GetValue(this); 1755 if (objectDependentsListMap != null) 1756 { 1757 FrugalMap dependentListMap = (FrugalMap)objectDependentsListMap; 1758 object dependentList = dependentListMap[dp.GlobalIndex]; 1759 Debug.Assert(dependentList != null, "dependentList should either be unset or non-null"); 1760 1761 if (dependentList != DependencyProperty.UnsetValue) 1762 { 1763 // The list can "go empty" if the items it references "went away" 1764 if (((DependentList)dependentList).IsEmpty) 1765 dependentListMap[dp.GlobalIndex] = DependencyProperty.UnsetValue; 1766 else 1767 ((DependentList)dependentList).InvalidateDependents(this, args); 1768 } 1769 1770 // also notify "direct" dependents 1771 dp = DirectDependencyProperty; 1772 dependentList = dependentListMap[dp.GlobalIndex]; 1773 Debug.Assert(dependentList != null, "dependentList should either be unset or non-null"); 1774 1775 if (dependentList != DependencyProperty.UnsetValue) 1776 { 1777 // The list can "go empty" if the items it references "went away" 1778 if (((DependentList)dependentList).IsEmpty) 1779 dependentListMap[dp.GlobalIndex] = DependencyProperty.UnsetValue; 1780 else 1781 ((DependentList)dependentList).InvalidateDependents(this, new DependencyPropertyChangedEventArgs(dp, (PropertyMetadata)null, null)); 1782 } 1783 } 1784 } 1785 } 1786 1787 1788 private EffectiveValueEntry EvaluateExpression( 1789 EntryIndex entryIndex, 1790 DependencyProperty dp, 1791 Expression expr, 1792 PropertyMetadata metadata, 1793 EffectiveValueEntry oldEntry, 1794 EffectiveValueEntry newEntry) 1795 { 1796 object value = expr.GetValue(this, dp); 1797 bool isDeferredReference = false; 1798 1799 if (value != DependencyProperty.UnsetValue && value != Expression.NoValue) 1800 { 1801 isDeferredReference = (value is DeferredReference); 1802 if (!isDeferredReference && !dp.IsValidValue(value)) 1803 { 1804 #region EventTracing 1805 #if VERBOSE_PROPERTY_EVENT 1806 if (isDynamicTracing) 1807 { 1808 if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 1809 { 1810 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYGUID, 1811 MS.Utility.EventType.EndEvent, 1812 EventTrace.PROPERTYVALIDATION, 0xFFF ); 1813 } 1814 } 1815 #endif 1816 #endregion EventTracing 1817 throw new InvalidOperationException(SR.Get(SRID.InvalidPropertyValue, value, dp.Name)); 1818 } 1819 } 1820 else 1821 { 1822 if (value == Expression.NoValue) 1823 { 1824 // The expression wants to "hide". First set the 1825 // expression value to NoValue to indicate "hiding". 1826 newEntry.SetExpressionValue(Expression.NoValue, expr); 1827 1828 // Next, get the expression value some other way. 1829 if (!dp.ReadOnly) 1830 { 1831 EvaluateBaseValueCore(dp, metadata, ref newEntry); 1832 value = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 1833 } 1834 else 1835 { 1836 value = DependencyProperty.UnsetValue; 1837 } 1838 } 1839 1840 // if there is still no value, use the default 1841 if (value == DependencyProperty.UnsetValue) 1842 { 1843 value = metadata.GetDefaultValue(this, dp); 1844 } 1845 } 1846 1847 // Set the expr and its evaluated value into 1848 // the _effectiveValues cache 1849 newEntry.SetExpressionValue(value, expr); 1850 return newEntry; 1851 } 1852 1853 //[CodeAnalysis("AptcaMethodsShouldOnlyCallAptcaMethods")] //Tracking Bug: 29647 1854 private EffectiveValueEntry EvaluateEffectiveValue( 1855 EntryIndex entryIndex, 1856 DependencyProperty dp, 1857 PropertyMetadata metadata, 1858 EffectiveValueEntry oldEntry, 1859 EffectiveValueEntry newEntry, // this is only used to recognize if this is a clear local value 1860 OperationType operationType) 1861 { 1862 #region EventTracing 1863 #if VERBOSE_PROPERTY_EVENT 1864 bool isDynamicTracing = EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose); // This was under "normal" 1865 if (isDynamicTracing) 1866 { 1867 ++ValidationCount; 1868 if( ValidationCount % 100 == 0 ) 1869 { 1870 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYVALIDATIONGUID, 1871 MS.Utility.EventType.Info, 1872 ValidationCount ); 1873 } 1874 1875 string TypeAndName = String.Format(CultureInfo.InvariantCulture, "[{0}]{1}({2})",GetType().Name,dp.Name,base.GetHashCode()); // FxCop wanted the CultureInfo.InvariantCulture 1876 1877 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYVALIDATIONGUID, 1878 MS.Utility.EventType.StartEvent, 1879 base.GetHashCode(), TypeAndName ); // base.GetHashCode() to avoid calling a virtual, which FxCop doesn't like. 1880 } 1881 #endif 1882 #endregion EventTracing 1883 1884 #if NESTED_OPERATIONS_CHECK 1885 // Are we validating out of control? 1886 if( NestedOperations > NestedOperationMaximum ) 1887 { 1888 // We're validating out of control, time to abort. 1889 throw new InvalidOperationException("Too many levels of nested DependencyProperty GetValue calls. This usually indicates a circular reference in the application and the cycle needs to be broken."); 1890 } 1891 NestedOperations++; // Decrement in the finally block 1892 #endif 1893 1894 object value = DependencyProperty.UnsetValue; 1895 1896 try 1897 { 1898 // Read local storage 1899 bool isSetValue = (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Local); 1900 bool isClearLocalValue = isSetValue && (newEntry.Value == DependencyProperty.UnsetValue); 1901 bool oldLocalIsExpression = false; 1902 bool preserveCurrentValue; 1903 1904 // honor request for "preserve current value" behaviour - see InvalidateProperty. 1905 if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown && 1906 newEntry.IsCoercedWithCurrentValue) 1907 { 1908 preserveCurrentValue = true; 1909 newEntry.IsCoercedWithCurrentValue = false; // clear flag only used for private communication 1910 } 1911 else 1912 { 1913 preserveCurrentValue = false; 1914 } 1915 1916 if (isClearLocalValue) 1917 { 1918 newEntry.BaseValueSourceInternal = BaseValueSourceInternal.Unknown; 1919 } 1920 else 1921 { 1922 // if we reached this on a re-evaluate of a setvalue, we need to make sure 1923 // we don't lose track of the newly specified local value. 1924 // for all other cases, the oldEntry will have the local value we should 1925 // use. 1926 value = isSetValue ? newEntry.LocalValue : oldEntry.LocalValue; 1927 1928 if (value == ExpressionInAlternativeStore) 1929 { 1930 value = DependencyProperty.UnsetValue; 1931 } 1932 else 1933 { 1934 oldLocalIsExpression = isSetValue ? newEntry.IsExpression : oldEntry.IsExpression; 1935 } 1936 } 1937 1938 // (If local storage not Unset and not an Expression, return) 1939 if (value != DependencyProperty.UnsetValue) 1940 { 1941 newEntry = new EffectiveValueEntry(dp, BaseValueSourceInternal.Local); 1942 newEntry.Value = value; 1943 1944 // Check if an Expression is set 1945 if (oldLocalIsExpression) 1946 { 1947 // CALLBACK 1948 newEntry = EvaluateExpression( 1949 entryIndex, 1950 dp, 1951 (Expression) value, 1952 metadata, 1953 oldEntry, 1954 newEntry); 1955 1956 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 1957 1958 value = newEntry.ModifiedValue.ExpressionValue; 1959 } 1960 } 1961 1962 // Subclasses are not allowed to resolve/modify the value for read-only properties. 1963 if( !dp.ReadOnly ) 1964 { 1965 // Give subclasses a chance to resolve/modify the value 1966 EvaluateBaseValueCore(dp, metadata, ref newEntry); 1967 1968 // we need to have the default value in the entry before we do the animation check 1969 if (newEntry.BaseValueSourceInternal == BaseValueSourceInternal.Unknown) 1970 { 1971 newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 1972 } 1973 1974 value = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 1975 1976 // preserve a current value across invalidations that don't change 1977 // the base value 1978 if (preserveCurrentValue && 1979 oldEntry.IsCoercedWithCurrentValue && 1980 oldEntry.BaseValueSourceInternal == newEntry.BaseValueSourceInternal && 1981 Equals(dp, oldEntry.ModifiedValue.BaseValue, value)) 1982 { 1983 object currentValue = oldEntry.ModifiedValue.CoercedValue; 1984 newEntry.SetCoercedValue(currentValue, value, skipBaseValueChecks:true, coerceWithCurrentValue:true); 1985 value = currentValue; 1986 } 1987 1988 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 1989 1990 if (oldEntry.IsAnimated) 1991 { 1992 newEntry.ResetCoercedValue(); 1993 EvaluateAnimatedValueCore(dp, metadata, ref newEntry); 1994 value = newEntry.GetFlattenedEntry(RequestFlags.FullyResolved).Value; 1995 } 1996 } 1997 } 1998 finally 1999 { 2000 #if NESTED_OPERATIONS_CHECK 2001 NestedOperations--; 2002 #endif 2003 } 2004 2005 #region EventTracing 2006 #if VERBOSE_PROPERTY_EVENT 2007 if (isDynamicTracing) 2008 { 2009 if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose)) 2010 { 2011 int UsingDefault = 1; 2012 if (value != DependencyProperty.UnsetValue) 2013 UsingDefault = 0; 2014 EventTrace.EventProvider.TraceEvent(EventTrace.PROPERTYVALIDATIONGUID, 2015 MS.Utility.EventType.EndEvent, 2016 UsingDefault); 2017 } 2018 } 2019 #endif 2020 #endregion EventTracing 2021 2022 if (value == DependencyProperty.UnsetValue) 2023 { 2024 newEntry = EffectiveValueEntry.CreateDefaultValueEntry(dp, metadata.GetDefaultValue(this, dp)); 2025 } 2026 2027 return newEntry; 2028 } 2029 2030 /// <summary> 2031 /// Allows subclasses to participate in property base value computation 2032 /// </summary> 2033 internal virtual void EvaluateBaseValueCore( 2034 DependencyProperty dp, 2035 PropertyMetadata metadata, 2036 ref EffectiveValueEntry newEntry) 2037 { 2038 } 2039 2040 /// <summary> 2041 /// Allows subclasses to participate in property animated value computation 2042 /// </summary> 2043 internal virtual void EvaluateAnimatedValueCore( 2044 DependencyProperty dp, 2045 PropertyMetadata metadata, 2046 ref EffectiveValueEntry newEntry) 2047 { 2048 } 2049 2050 /// <summary> 2051 /// Notification that a specified property has been changed 2052 /// </summary> 2053 /// <param name="e">EventArgs that contains the property, metadata, old value, and new value for this change</param> 2054 protected virtual void OnPropertyChanged(DependencyPropertyChangedEventArgs e) 2055 { 2056 // Do not call VerifyAccess because this is a virtual, and is used as a call-out. 2057 2058 if( e.Property == null ) 2059 { 2060 throw new ArgumentException(SR.Get(SRID.ReferenceIsNull, "e.Property"), "e"); 2061 } 2062 2063 if (e.IsAValueChange || e.IsASubPropertyChange || e.OperationType == OperationType.ChangeMutableDefaultValue) 2064 { 2065 // Inform per-type/property invalidation listener, if exists 2066 PropertyMetadata metadata = e.Metadata; 2067 if ((metadata != null) && (metadata.PropertyChangedCallback != null)) 2068 { 2069 metadata.PropertyChangedCallback(this, e); 2070 } 2071 } 2072 } 2073 2074 /// <summary> 2075 /// Override this method to control whether a DependencyProperty should be serialized. 2076 /// The base implementation returns true if the property is set (locally) on this object. 2077 /// </summary> 2078 protected internal virtual bool ShouldSerializeProperty( DependencyProperty dp ) 2079 { 2080 return ContainsValue( dp ); 2081 } 2082 2083 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 2084 internal BaseValueSourceInternal GetValueSource(DependencyProperty dp, PropertyMetadata metadata, out bool hasModifiers) 2085 { 2086 bool isExpression, isAnimated, isCoerced, isCurrent; 2087 return GetValueSource(dp, metadata, out hasModifiers, out isExpression, out isAnimated, out isCoerced, out isCurrent); 2088 } 2089 2090 [FriendAccessAllowed] // Built into Base, also used by Core & Framework. 2091 internal BaseValueSourceInternal GetValueSource(DependencyProperty dp, PropertyMetadata metadata, 2092 out bool hasModifiers, out bool isExpression, out bool isAnimated, out bool isCoerced, out bool isCurrent) 2093 { 2094 if (dp == null) 2095 { 2096 throw new ArgumentNullException("dp"); 2097 } 2098 2099 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 2100 2101 if (entryIndex.Found) 2102 { 2103 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 2104 hasModifiers = entry.HasModifiers; 2105 isExpression = entry.IsExpression; 2106 isAnimated = entry.IsAnimated; 2107 isCoerced = entry.IsCoerced; 2108 isCurrent = entry.IsCoercedWithCurrentValue; 2109 return entry.BaseValueSourceInternal; 2110 } 2111 else 2112 { 2113 isExpression = false; 2114 isAnimated = false; 2115 isCoerced = false; 2116 isCurrent = false; 2117 2118 if (dp.ReadOnly) 2119 { 2120 if (metadata == null) 2121 { 2122 metadata = dp.GetMetadata(DependencyObjectType); 2123 } 2124 2125 GetReadOnlyValueCallback callback = metadata.GetReadOnlyValueCallback; 2126 if (callback != null) 2127 { 2128 BaseValueSourceInternal source; 2129 callback(this, out source); 2130 hasModifiers = false; 2131 return source; 2132 } 2133 } 2134 2135 if (dp.IsPotentiallyInherited) 2136 { 2137 if (metadata == null) 2138 { 2139 metadata = dp.GetMetadata(DependencyObjectType); 2140 } 2141 2142 if (metadata.IsInherited) 2143 { 2144 DependencyObject inheritanceParent = InheritanceParent; 2145 if (inheritanceParent != null && inheritanceParent.LookupEntry(dp.GlobalIndex).Found) 2146 { 2147 hasModifiers = false; 2148 return BaseValueSourceInternal.Inherited; 2149 } 2150 } 2151 } 2152 } 2153 2154 hasModifiers = false; 2155 return BaseValueSourceInternal.Default; 2156 } 2157 2158 /// <summary> 2159 /// Retrieve the local value of a property (if set) 2160 /// </summary> 2161 /// <param name="dp">Dependency property</param> 2162 /// <returns> 2163 /// The local value. DependencyProperty.UnsetValue if no local value was 2164 /// set via <cref see="SetValue"/>. 2165 /// </returns> 2166 public object ReadLocalValue(DependencyProperty dp) 2167 { 2168 // Do not allow foreign threads access. 2169 // (This is a noop if this object is not assigned to a Dispatcher.) 2170 // 2171 this.VerifyAccess(); 2172 2173 if (dp == null) 2174 { 2175 throw new ArgumentNullException("dp"); 2176 } 2177 2178 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 2179 2180 // Call Forwarded 2181 return ReadLocalValueEntry(entryIndex, dp, false /* allowDeferredReferences */); 2182 } 2183 2184 /// <summary> 2185 /// Retrieve the local value of a property (if set) 2186 /// </summary> 2187 /// <returns> 2188 /// The local value. DependencyProperty.UnsetValue if no local value was 2189 /// set via <cref see="SetValue"/>. 2190 /// </returns> 2191 internal object ReadLocalValueEntry(EntryIndex entryIndex, DependencyProperty dp, bool allowDeferredReferences) 2192 { 2193 if (!entryIndex.Found) 2194 { 2195 return DependencyProperty.UnsetValue; 2196 } 2197 2198 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 2199 object value = entry.IsCoercedWithCurrentValue ? entry.ModifiedValue.CoercedValue : entry.LocalValue; 2200 2201 // convert a deferred reference into a real value 2202 if (!allowDeferredReferences && entry.IsDeferredReference) 2203 { 2204 // localValue may still not be a DeferredReference, e.g. 2205 // if it is an expression whose value is a DeferredReference. 2206 // So a little more work is needed before converting the value. 2207 DeferredReference dr = value as DeferredReference; 2208 if (dr != null) 2209 { 2210 value = dr.GetValue(entry.BaseValueSourceInternal); 2211 } 2212 } 2213 2214 // treat Expression marker as "unset" 2215 if (value == ExpressionInAlternativeStore) 2216 { 2217 value = DependencyProperty.UnsetValue; 2218 } 2219 2220 return value; 2221 } 2222 2223 /// <summary> 2224 /// Create a local value enumerator for this instance 2225 /// </summary> 2226 /// <returns>Local value enumerator (stack based)</returns> 2227 public LocalValueEnumerator GetLocalValueEnumerator() 2228 { 2229 // Do not allow foreign threads access. 2230 // (This is a noop if this object is not assigned to a Dispatcher.) 2231 // 2232 this.VerifyAccess(); 2233 2234 uint effectiveValuesCount = EffectiveValuesCount; 2235 LocalValueEntry[] snapshot = new LocalValueEntry[effectiveValuesCount]; 2236 int count = 0; 2237 2238 // Iterate through the sorted effectiveValues 2239 for (uint i=0; i<effectiveValuesCount; i++) 2240 { 2241 DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[_effectiveValues[i].PropertyIndex]; 2242 if (dp != null) 2243 { 2244 object localValue = ReadLocalValueEntry(new EntryIndex(i), dp, false /* allowDeferredReferences */); 2245 if (localValue != DependencyProperty.UnsetValue) 2246 { 2247 snapshot[count++] = new LocalValueEntry(dp, localValue); 2248 } 2249 } 2250 } 2251 2252 return new LocalValueEnumerator(snapshot, count); 2253 } 2254 2255 /// <summary> 2256 /// This is how we track if someone is enumerating the _effectiveValues 2257 /// cache. This flag should be set to false before doing that. 2258 /// </summary> 2259 private bool CanModifyEffectiveValues 2260 { 2261 get { return (_packedData & 0x00080000) != 0; } 2262 2263 set 2264 { 2265 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 2266 2267 if (value) 2268 { 2269 _packedData |= 0x00080000; 2270 } 2271 else 2272 { 2273 _packedData &= 0xFFF7FFFF; 2274 } 2275 } 2276 } 2277 2278 [FriendAccessAllowed] // defined in Base, used in Core and Framework 2279 internal bool IsInheritanceContextSealed 2280 { 2281 get { return (_packedData & 0x01000000) != 0; } 2282 set 2283 { 2284 if (value) 2285 { 2286 _packedData |= 0x01000000; 2287 } 2288 else 2289 { 2290 _packedData &= 0xFEFFFFFF; 2291 } 2292 } 2293 } 2294 2295 private bool DO_Sealed 2296 { 2297 get { return (_packedData & 0x00400000) != 0; } 2298 set { if (value) { _packedData |= 0x00400000; } else { _packedData &= 0xFFBFFFFF; } } 2299 } 2300 2301 // Freezable State stored here for size optimization: 2302 // Freezable is immutable 2303 internal bool Freezable_Frozen 2304 { 2305 // uses the same bit as Sealed ... even though they are not quite synonymous 2306 // Since Frozen implies Sealed, and calling Seal() is disallowed on Freezable, 2307 // this is ok. 2308 get { return DO_Sealed; } 2309 set { DO_Sealed = value; } 2310 } 2311 2312 // Freezable State stored here for size optimization: 2313 // Freezable is being referenced in multiple places and hence cannot have a single InheritanceContext 2314 internal bool Freezable_HasMultipleInheritanceContexts 2315 { 2316 get { return (_packedData & 0x02000000) != 0; } 2317 set { if (value) { _packedData |= 0x02000000; } else { _packedData &= 0xFDFFFFFF; } } 2318 } 2319 2320 // Freezable State stored here for size optimization: 2321 // Handlers stored in a dictionary 2322 internal bool Freezable_UsingHandlerList 2323 { 2324 get { return (_packedData & 0x04000000) != 0; } 2325 set { if (value) { _packedData |= 0x04000000; } else { _packedData &= 0xFBFFFFFF; } } 2326 } 2327 2328 // Freezable State stored here for size optimization: 2329 // Context stored in a dictionary 2330 internal bool Freezable_UsingContextList 2331 { 2332 get { return (_packedData & 0x08000000) != 0; } 2333 set { if (value) { _packedData |= 0x08000000; } else { _packedData &= 0xF7FFFFFF; } } 2334 } 2335 2336 // Freezable State stored here for size optimization: 2337 // Freezable has a single handler 2338 internal bool Freezable_UsingSingletonHandler 2339 { 2340 get { return (_packedData & 0x10000000) != 0; } 2341 set { if (value) { _packedData |= 0x10000000; } else { _packedData &= 0xEFFFFFFF; } } 2342 } 2343 2344 // Freezable State stored here for size optimization: 2345 // Freezable has a single context 2346 internal bool Freezable_UsingSingletonContext 2347 { 2348 get { return (_packedData & 0x20000000) != 0; } 2349 set { if (value) { _packedData |= 0x20000000; } else { _packedData &= 0xDFFFFFFF; } } 2350 } 2351 2352 2353 // Animatable State stored here for size optimization: 2354 // 2355 internal bool Animatable_IsResourceInvalidationNecessary 2356 { 2357 [FriendAccessAllowed] // Built into Base, but used by Core. 2358 get { return (_packedData & 0x40000000) != 0; } 2359 [FriendAccessAllowed] // Built into Base, but used by Core. 2360 set { if (value) { _packedData |= 0x40000000; } else { _packedData &= 0xBFFFFFFF; } } 2361 } 2362 2363 // IAnimatable State stored here for size optimization: 2364 // Returns true if this IAnimatable implemention has animations on its properties 2365 // but doesn't check the sub-properties for animations. 2366 internal bool IAnimatable_HasAnimatedProperties 2367 { 2368 [FriendAccessAllowed] // Built into Base, but used by Core. 2369 get { return (_packedData & 0x80000000) != 0; } 2370 [FriendAccessAllowed] // Built into Base, but used by Core. 2371 set { if (value) { _packedData |= 0x80000000; } else { _packedData &= 0x7FFFFFFF; } } 2372 } 2373 2374 // internal DP used for direct dependencies (should never appear in an effective value table) 2375 // 2376 // A direct dependency can arise from WPF data binding in a situation like this: 2377 // <Border Background="{Binding Path=Brush}"/> 2378 // when the Brush property on the source object is not a DP, but just a regular CLR property. 2379 // If a property on the brush changes, the border should be notified so that 2380 // it can repaint its background. The brush is notified of the change, and 2381 // propagtes the notification (as a SubPropertyChange) to all its customers that 2382 // use the brush via a DP, but this isn't enough for the current scenario. 2383 // To overcome this, the binding registers itself as a "direct" dependent of the brush 2384 // (using the following DP as the key). The property engine will forward 2385 // notifications to direct dependents, the binding will hear about the change, 2386 // and will forward a sub-property change to the Border. 2387 [FriendAccessAllowed] // Built into Base, also used by Framework. 2388 static internal readonly DependencyProperty DirectDependencyProperty = 2389 DependencyProperty.Register("__Direct", typeof(object), typeof(DependencyProperty)); 2390 2391 internal static void UpdateSourceDependentLists(DependencyObject d, DependencyProperty dp, DependencySource[] sources, Expression expr, bool add) 2392 { 2393 // Sources already validated to be on the same thread as Dependent (d) 2394 2395 if (sources != null) 2396 { 2397 // don't hold a reference on the dependent if the expression is doing 2398 // the invalidations. This helps avoid memory leaks (bug 871139) 2399 if (expr.ForwardsInvalidations) 2400 { 2401 d = null; 2402 dp = null; 2403 } 2404 2405 for (int i = 0; i < sources.Length; i++) 2406 { 2407 DependencySource source = sources[i]; 2408 2409 // A Sealed DependencyObject does not have a Dependents list 2410 // so don't bother updating it (or attempt to add one). 2411 2412 Debug.Assert((!source.DependencyObject.IsSealed) || 2413 (DependentListMapField.GetValue(source.DependencyObject) == default(object))); 2414 2415 if (!source.DependencyObject.IsSealed) 2416 { 2417 // Retrieve the DependentListMap for this source 2418 // The list of dependents to invalidate is stored using a special negative key 2419 2420 FrugalMap dependentListMap; 2421 object value = DependentListMapField.GetValue(source.DependencyObject); 2422 if (value != null) 2423 { 2424 dependentListMap = (FrugalMap)value; 2425 } 2426 else 2427 { 2428 dependentListMap = new FrugalMap(); 2429 } 2430 2431 // Get list of DependentList off of ID map of Source 2432 object dependentListObj = dependentListMap[source.DependencyProperty.GlobalIndex]; 2433 Debug.Assert(dependentListObj != null, "dependentList should either be unset or non-null"); 2434 2435 // Add/Remove new Dependent (this) to Source's list 2436 if (add) 2437 { 2438 DependentList dependentList; 2439 if (dependentListObj == DependencyProperty.UnsetValue) 2440 { 2441 dependentListMap[source.DependencyProperty.GlobalIndex] = dependentList = new DependentList(); 2442 } 2443 else 2444 { 2445 dependentList = (DependentList)dependentListObj; 2446 } 2447 2448 dependentList.Add(d, dp, expr); 2449 } 2450 else 2451 { 2452 if (dependentListObj != DependencyProperty.UnsetValue) 2453 { 2454 DependentList dependentList = (DependentList)dependentListObj; 2455 2456 dependentList.Remove(d, dp, expr); 2457 2458 if (dependentList.IsEmpty) 2459 { 2460 // No more dependencies for this property; reclaim the space if we can. 2461 dependentListMap[source.DependencyProperty.GlobalIndex] = DependencyProperty.UnsetValue; 2462 } 2463 } 2464 } 2465 2466 // Set the updated struct back into the source's _localStore. 2467 DependentListMapField.SetValue(source.DependencyObject, dependentListMap); 2468 } 2469 } 2470 } 2471 } 2472 2473 internal static void ValidateSources(DependencyObject d, DependencySource[] newSources, Expression expr) 2474 { 2475 // Make sure all Sources are owned by the same thread. 2476 if (newSources != null) 2477 { 2478 Dispatcher dispatcher = d.Dispatcher; 2479 for (int i = 0; i < newSources.Length; i++) 2480 { 2481 Dispatcher sourceDispatcher = newSources[i].DependencyObject.Dispatcher; 2482 if (sourceDispatcher != dispatcher && !(expr.SupportsUnboundSources && sourceDispatcher == null)) 2483 { 2484 throw new ArgumentException(SR.Get(SRID.SourcesMustBeInSameThread)); 2485 } 2486 } 2487 } 2488 } 2489 2490 /// <summary> 2491 /// Register the two callbacks that are used to implement the "alternative 2492 /// Expression storage" feature, and return the two methods used to access 2493 /// the feature. 2494 /// </summary> 2495 /// <remarks> 2496 /// This method should only be called (once) from the Framework. It should 2497 /// not be called directly by users. 2498 /// </remarks> 2499 [FriendAccessAllowed] // Built into Base, also used by Framework. 2500 internal static void RegisterForAlternativeExpressionStorage( 2501 AlternativeExpressionStorageCallback getExpressionCore, 2502 out AlternativeExpressionStorageCallback getExpression) 2503 { 2504 Debug.Assert(getExpressionCore != null, "getExpressionCore cannot be null"); 2505 Debug.Assert(_getExpressionCore == null, "The 'alternative Expression storage' feature has already been registered"); 2506 2507 _getExpressionCore = getExpressionCore; 2508 2509 getExpression = new AlternativeExpressionStorageCallback(GetExpression); 2510 } 2511 2512 /// <summary> 2513 /// Used to determine whether a DependencyObject has a value with an expression, such as a resource reference. 2514 /// </summary> 2515 /// <returns> 2516 /// True if Dependency object has a value with an expression 2517 /// </returns> 2518 internal bool HasAnyExpression() 2519 { 2520 EffectiveValueEntry[] effectiveValues = EffectiveValues; 2521 uint numEffectiveValues = EffectiveValuesCount; 2522 bool result = false; 2523 2524 for (uint i = 0; i < numEffectiveValues; i++) 2525 { 2526 DependencyProperty dp = 2527 DependencyProperty.RegisteredPropertyList.List[effectiveValues[i].PropertyIndex]; 2528 2529 if (dp != null) 2530 { 2531 EntryIndex entryIndex = new EntryIndex(i); 2532 // The expression check only needs to be done when isChecking is true 2533 // because if we return false here the Freeze() call will fail. 2534 if (HasExpression(entryIndex, dp)) 2535 { 2536 result = true; 2537 break; 2538 } 2539 } 2540 } 2541 2542 return result; 2543 } 2544 2545 /// <summary> 2546 /// Return true iff the property has an expression applied to it. 2547 /// </summary> 2548 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 2549 internal bool HasExpression(EntryIndex entryIndex, DependencyProperty dp) 2550 { 2551 if (!entryIndex.Found) 2552 { 2553 return false; 2554 } 2555 2556 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 2557 2558 object o = entry.LocalValue; 2559 2560 bool result = (entry.HasExpressionMarker || o is Expression); 2561 return result; 2562 } 2563 2564 /// <summary> 2565 /// Return the Expression (if any) currently in effect for the given property. 2566 /// </summary> 2567 private static Expression GetExpression(DependencyObject d, DependencyProperty dp, PropertyMetadata metadata) 2568 { 2569 EntryIndex entryIndex = d.LookupEntry(dp.GlobalIndex); 2570 2571 if (!entryIndex.Found) 2572 { 2573 return null; 2574 } 2575 2576 EffectiveValueEntry entry = d._effectiveValues[entryIndex.Index]; 2577 2578 if (entry.HasExpressionMarker) 2579 { 2580 if (_getExpressionCore != null) 2581 { 2582 return _getExpressionCore(d, dp, metadata); 2583 } 2584 2585 return null; 2586 } 2587 2588 // no expression marker -- check local value itself 2589 if (entry.IsExpression) 2590 { 2591 return (Expression) entry.LocalValue; 2592 } 2593 2594 return null; 2595 } 2596 2597 #region InheritanceContext 2598 2599 /// <summary> 2600 /// InheritanceContext 2601 /// </summary> 2602 internal virtual DependencyObject InheritanceContext 2603 { 2604 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 2605 get { return null; } 2606 } 2607 2608 /// <summary> 2609 /// You have a new InheritanceContext 2610 /// </summary> 2611 /// <remarks> 2612 /// This method is equivalent to OnNewParent of 2613 /// the yesteryears on an element. Note that the 2614 /// implementation may choose to ignore this new 2615 /// context, e.g. in the case of a Freezable that 2616 /// is being shared. 2617 /// <p/> 2618 /// Do not call this method directly. Instead call 2619 /// ProvideSelfAsInheritanceContext, which checks various 2620 /// preconditions and then calls AddInheritanceContext for you. 2621 /// </remarks> 2622 internal virtual void AddInheritanceContext(DependencyObject context, DependencyProperty property) 2623 { 2624 } 2625 2626 /// <summary> 2627 /// You have lost an InheritanceContext 2628 /// </summary> 2629 /// <remarks> 2630 /// <p/> 2631 /// Do not call this method directly. Instead call 2632 /// RemoveSelfAsInheritanceContext, which checks various 2633 /// preconditions and then calls RemoveInheritanceContext for you. 2634 /// </remarks> 2635 internal virtual void RemoveInheritanceContext(DependencyObject context, DependencyProperty property) 2636 { 2637 } 2638 2639 /// <summary> 2640 /// You are about to provided as the InheritanceContext for the target. 2641 /// You can choose to allow this or not. 2642 /// </summary> 2643 internal virtual bool ShouldProvideInheritanceContext(DependencyObject target, DependencyProperty property) 2644 { 2645 return true; 2646 } 2647 2648 /// <summary> 2649 /// The InheritanceContext for an ancestor 2650 /// has changed 2651 /// </summary> 2652 /// <remarks> 2653 /// This is the equivalent of OnAncestorChanged 2654 /// for an element 2655 /// </remarks> 2656 [FriendAccessAllowed] // Built into Base, also used by Core. 2657 internal void OnInheritanceContextChanged(EventArgs args) 2658 { 2659 // Fire the event that BindingExpression and 2660 // ResourceReferenceExpression will be listening to. 2661 EventHandler handlers = InheritanceContextChangedHandlersField.GetValue(this); 2662 if (handlers != null) 2663 { 2664 handlers(this, args); 2665 } 2666 2667 CanModifyEffectiveValues = false; 2668 try 2669 { 2670 // Notify all those DO that the current instance is a 2671 // context for (we will call these inheritanceChildren) about the 2672 // change in the context. This is like a recursive tree walk. 2673 // Iterate through the sorted effectiveValues 2674 uint effectiveValuesCount = EffectiveValuesCount; 2675 for (uint i=0; i<effectiveValuesCount; i++) 2676 { 2677 DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[_effectiveValues[i].PropertyIndex]; 2678 if (dp != null) 2679 { 2680 object localValue = ReadLocalValueEntry(new EntryIndex(i), dp, true /* allowDeferredReferences */); 2681 if (localValue != DependencyProperty.UnsetValue) 2682 { 2683 DependencyObject inheritanceChild = localValue as DependencyObject; 2684 if (inheritanceChild!= null && inheritanceChild.InheritanceContext == this) 2685 { 2686 inheritanceChild.OnInheritanceContextChanged(args); 2687 } 2688 } 2689 } 2690 } 2691 } 2692 finally 2693 { 2694 Debug.Assert(CanModifyEffectiveValues == false, "We do not expect re-entrancy here."); 2695 CanModifyEffectiveValues = true; 2696 } 2697 2698 // Let sub-classes do their own thing 2699 OnInheritanceContextChangedCore(args); 2700 } 2701 2702 /// <summary> 2703 /// This is a means for subclasses to get notification 2704 /// of InheritanceContext changes and then they can do 2705 /// their own thing. 2706 /// </summary> 2707 [FriendAccessAllowed] // Built into Base, also used by Core. 2708 internal virtual void OnInheritanceContextChangedCore(EventArgs args) 2709 { 2710 } 2711 2712 /// <summary> 2713 /// Event for InheritanceContextChanged. This is 2714 /// the event that BindingExpression and 2715 /// ResourceReferenceExpressions will be listening to. 2716 /// </summary> 2717 /// <remarks> 2718 /// make this pay-for-play by storing handlers 2719 /// in an uncommon field 2720 /// </remarks> 2721 internal event EventHandler InheritanceContextChanged 2722 { 2723 [FriendAccessAllowed] // Built into Base, also used by Framework. 2724 add 2725 { 2726 // Get existing event hanlders 2727 EventHandler handlers = InheritanceContextChangedHandlersField.GetValue(this); 2728 if (handlers != null) 2729 { 2730 // combine to a multicast delegate 2731 handlers = (EventHandler)Delegate.Combine(handlers, value); 2732 } 2733 else 2734 { 2735 handlers = value; 2736 } 2737 // Set the delegate as an uncommon field 2738 InheritanceContextChangedHandlersField.SetValue(this, handlers); 2739 } 2740 2741 [FriendAccessAllowed] // Built into Base, also used by Framework. 2742 remove 2743 { 2744 // Get existing event hanlders 2745 EventHandler handlers = InheritanceContextChangedHandlersField.GetValue(this); 2746 if (handlers != null) 2747 { 2748 // Remove the given handler 2749 handlers = (EventHandler)Delegate.Remove(handlers, value); 2750 if (handlers == null) 2751 { 2752 // Clear the value for the uncommon field 2753 // cause there are no more handlers 2754 InheritanceContextChangedHandlersField.ClearValue(this); 2755 } 2756 else 2757 { 2758 // Set the remaining handlers as an uncommon field 2759 InheritanceContextChangedHandlersField.SetValue(this, handlers); 2760 } 2761 } 2762 } 2763 } 2764 2765 /// <summary> 2766 /// By default this is false since it doesn't have a context 2767 /// </summary> 2768 internal virtual bool HasMultipleInheritanceContexts 2769 { 2770 get { return false; } 2771 } 2772 2773 /// <summary> 2774 /// By default this is true since every DependencyObject can be an InheritanceContext 2775 /// </summary> 2776 internal bool CanBeInheritanceContext 2777 { 2778 [FriendAccessAllowed] // Built into Base, also used by Framework. 2779 get { return (_packedData & 0x00200000) != 0; } 2780 2781 [FriendAccessAllowed] // Built into Base, also used by Framework. 2782 set 2783 { 2784 if (value) 2785 { 2786 _packedData |= 0x00200000; 2787 } 2788 else 2789 { 2790 _packedData &= 0xFFDFFFFF; 2791 } 2792 } 2793 } 2794 2795 [FriendAccessAllowed] // Built into Base, also used by Framework. 2796 internal static bool IsTreeWalkOperation(OperationType operation) 2797 { 2798 return operation == OperationType.AddChild || 2799 operation == OperationType.RemoveChild || 2800 operation == OperationType.Inherit; 2801 } 2802 2803 /// <summary> 2804 /// Debug-only method that asserts that the current DO does not have any 2805 /// listeners on its InheritanceContextChanged event. This is used by 2806 /// Freezable (frozen Freezables can't have listeners). 2807 /// </summary> 2808 [Conditional ("DEBUG")] 2809 internal void Debug_AssertNoInheritanceContextListeners() 2810 { 2811 Debug.Assert(InheritanceContextChangedHandlersField.GetValue(this) == null, 2812 "This object should not have any listeners to its InheritanceContextChanged event"); 2813 } 2814 2815 // This uncommon field is used to store the handlers for the InheritanceContextChanged event 2816 private static readonly UncommonField<EventHandler> InheritanceContextChangedHandlersField = new UncommonField<EventHandler>(); 2817 2818 #endregion InheritanceContext 2819 2820 #region EffectiveValues 2821 2822 // The rest of DependencyObject is its EffectiveValues cache 2823 2824 // The cache of effective (aka "computed" aka "resolved") property 2825 // values for this DO. If a DP does not have an entry in this array 2826 // it means one of two things: 2827 // 1) if it's an inheritable property, then its value may come from 2828 // this DO's InheritanceParent 2829 // 2) if it's not an inheritable property (or this DO's InheritanceParent 2830 // doesn't have an entry for this DP either), then the value for 2831 // that DP on this DO is the default value. 2832 // Otherwise, the DP will have an entry in this array describing the 2833 // current value of the DP, where this value came from, and how it 2834 // has been modified 2835 internal EffectiveValueEntry[] EffectiveValues 2836 { 2837 [FriendAccessAllowed] // Built into Base, also used by Framework. 2838 get { return _effectiveValues; } 2839 } 2840 2841 // The total number of entries in the above EffectiveValues cache 2842 internal uint EffectiveValuesCount 2843 { 2844 [FriendAccessAllowed] // Built into Base, also used by Framework. 2845 get { return _packedData & 0x000003FF; } 2846 private set { _packedData = (_packedData & 0xFFFFFC00) | (value & 0x000003FF); } 2847 } 2848 2849 // The number of entries in the above EffectiveValues cache that 2850 // correspond to DPs that are inheritable on this DO; this count 2851 // helps us during "tree change" invalidations to know how big 2852 // of a "working change list" we have to construct. 2853 internal uint InheritableEffectiveValuesCount 2854 { 2855 [FriendAccessAllowed] // Built into Base, also used by Framework. 2856 get { return (_packedData >> 10) & 0x1FF; } 2857 set 2858 { 2859 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 2860 _packedData = ((value & 0x1FF) << 10) | (_packedData & 0xFFF803FF); 2861 } 2862 } 2863 2864 // This flag indicates whether or not we are in "Property Initialization 2865 // Mode". This is an opt-in mode: a DO starts out *not* in Property 2866 // Initialization Mode. In this mode, the EffectiveValues cache grows 2867 // at a more liberal (2.0) rate. Normally, outside of this mode, the 2868 // cache grows at a much stingier (1.2) rate. 2869 // Internal customers (currently only UIElement) access this mode 2870 // through the BeginPropertyInitialization/EndPropertyInitialization 2871 // methods below 2872 private bool IsInPropertyInitialization 2873 { 2874 get { return (_packedData & 0x00800000) != 0; } 2875 set 2876 { 2877 if (value) 2878 { 2879 _packedData |= 0x00800000; 2880 } 2881 else 2882 { 2883 _packedData &= 0xFF7FFFFF; 2884 } 2885 } 2886 } 2887 2888 // A DependencyObject calls this method to indicate to the property 2889 // system that a bunch of property sets are about to happen; the 2890 // property system responds by elevating the growth rate of the 2891 // EffectiveValues cache, to speed up initialization by requiring 2892 // fewer reallocations 2893 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 2894 internal void BeginPropertyInitialization() 2895 { 2896 IsInPropertyInitialization = true; 2897 } 2898 2899 // A DependencyObject calls this method to indicate to the property 2900 // system that it is now done with the bunch of property sets that 2901 // accompanied the initialization of this element; the property 2902 // system responds by returning the growth rate of the 2903 // EffectiveValues cache to its normal rate, and then trimming 2904 // the cache to get rid of any excess bloat incurred by the 2905 // aggressive growth rate during initialization mode. 2906 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 2907 internal void EndPropertyInitialization() 2908 { 2909 IsInPropertyInitialization = false; 2910 2911 if (_effectiveValues != null) 2912 { 2913 uint effectiveValuesCount = EffectiveValuesCount; 2914 if (effectiveValuesCount != 0) 2915 { 2916 uint endLength = effectiveValuesCount; 2917 if (((float) endLength / (float) _effectiveValues.Length) < 0.8) 2918 { 2919 // For thread-safety, sealed DOs can't modify _effectiveValues. 2920 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 2921 2922 EffectiveValueEntry[] destEntries = new EffectiveValueEntry[endLength]; 2923 Array.Copy(_effectiveValues, 0, destEntries, 0, effectiveValuesCount); 2924 _effectiveValues = destEntries; 2925 } 2926 } 2927 } 2928 } 2929 2930 2931 internal DependencyObject InheritanceParent 2932 { 2933 [FriendAccessAllowed] // Built into Base, also used by Framework. 2934 get 2935 { 2936 if ((_packedData & 0x3E100000) == 0) 2937 { 2938 return (DependencyObject) _contextStorage; 2939 } 2940 2941 // return null if this DO has any of the following set: 2942 // IsSelfInheritanceParent 2943 // Freezable_HasMultipleInheritanceContexts 2944 // Freezable_UsingHandlerList 2945 // Freezable_UsingContextList 2946 // Freezable_UsingSingletonHandler 2947 // Freezable_UsingSingletonContext 2948 return null; 2949 } 2950 } 2951 2952 private void SetInheritanceParent(DependencyObject newParent) 2953 { 2954 Debug.Assert((_packedData & 0x3E000000) == 0, "InheritanceParent should not be set in a Freezable, which manages its own inheritance context."); 2955 2956 // For thread-safety, sealed DOs can't modify _contextStorage 2957 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 2958 2959 if (_contextStorage != null) 2960 { 2961 Debug.Assert(!IsSelfInheritanceParent, "If the IsSelfInheritanceParent is set then the InheritanceParent should have been ----d."); 2962 2963 _contextStorage = newParent; 2964 } 2965 else 2966 { 2967 if (newParent != null) 2968 { 2969 // Merge all the inheritable properties on the inheritanceParent into the EffectiveValues 2970 // store on the current node because someone had set an effective value for an 2971 // inheritable property on this node. 2972 if (IsSelfInheritanceParent) 2973 { 2974 MergeInheritableProperties(newParent); 2975 } 2976 else 2977 { 2978 _contextStorage = newParent; 2979 } 2980 } 2981 else 2982 { 2983 // Do nothing because before and after values are both null 2984 } 2985 } 2986 } 2987 2988 2989 2990 internal bool IsSelfInheritanceParent 2991 { 2992 [FriendAccessAllowed] // Built into Base, also used by Framework. 2993 get { return (_packedData & 0x00100000) != 0; } 2994 } 2995 2996 // Currently we only have support for turning this flag on. Once set this flag never goes false after that. 2997 [FriendAccessAllowed] // Built into Base, also used by Framework. 2998 internal void SetIsSelfInheritanceParent() 2999 { 3000 // Merge all the inheritable properties on the inheritanceParent into the EffectiveValues 3001 // store on the current node because someone tried to set an effective value for an 3002 // inheritable property on this node. 3003 DependencyObject inheritanceParent = InheritanceParent; 3004 if (inheritanceParent != null) 3005 { 3006 MergeInheritableProperties(inheritanceParent); 3007 3008 // Get rid of the InheritanceParent since we won't need it anymore for 3009 // having cached all the inheritable properties on self 3010 SetInheritanceParent(null); 3011 } 3012 3013 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 3014 3015 _packedData |= 0x00100000; 3016 } 3017 3018 // 3019 // This method 3020 // 1. Recalculates the InheritanceParent with respect to the given FrameworkParent 3021 // 2. Is called from [FE/FCE].OnAncestorChangedInternal 3022 // 3023 [FriendAccessAllowed] // Built into Base, also used by Framework. 3024 internal void SynchronizeInheritanceParent(DependencyObject parent) 3025 { 3026 // If this flag is true it indicates that all the inheritable properties for this node 3027 // are cached on itself and hence we will not need the InheritanceParent pointer at all. 3028 if (!this.IsSelfInheritanceParent) 3029 { 3030 if (parent != null) 3031 { 3032 if (!parent.IsSelfInheritanceParent) 3033 { 3034 SetInheritanceParent(parent.InheritanceParent); 3035 } 3036 else 3037 { 3038 SetInheritanceParent(parent); 3039 } 3040 } 3041 else 3042 { 3043 SetInheritanceParent(null); 3044 } 3045 } 3046 } 3047 3048 // 3049 // This method 3050 // 1. Merges the inheritable properties from the parent into the EffectiveValues store on self 3051 // 3052 private void MergeInheritableProperties(DependencyObject inheritanceParent) 3053 { 3054 Debug.Assert(inheritanceParent != null, "Must have inheritanceParent"); 3055 Debug.Assert(inheritanceParent.IsSelfInheritanceParent, "An inheritanceParent should always be one that has all the inheritable properties cached on self"); 3056 3057 EffectiveValueEntry[] parentEffectiveValues = inheritanceParent.EffectiveValues; 3058 uint parentEffectiveValuesCount = inheritanceParent.EffectiveValuesCount; 3059 3060 for (uint i=0; i<parentEffectiveValuesCount; i++) 3061 { 3062 EffectiveValueEntry entry = parentEffectiveValues[i]; 3063 DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[entry.PropertyIndex]; 3064 3065 // There are UncommonFields also stored in the EffectiveValues cache. We need to exclude those. 3066 if (dp != null) 3067 { 3068 PropertyMetadata metadata = dp.GetMetadata(DependencyObjectType); 3069 if (metadata.IsInherited) 3070 { 3071 object value = inheritanceParent.GetValueEntry( 3072 new EntryIndex(i), 3073 dp, 3074 metadata, 3075 RequestFlags.SkipDefault | RequestFlags.DeferredReferences).Value; 3076 if (value != DependencyProperty.UnsetValue) 3077 { 3078 EntryIndex entryIndex = LookupEntry(dp.GlobalIndex); 3079 3080 SetEffectiveValue(entryIndex, dp, dp.GlobalIndex, metadata, value, BaseValueSourceInternal.Inherited); 3081 } 3082 } 3083 } 3084 } 3085 } 3086 3087 // 3088 // This method 3089 // 1. Is used to check if the given entryIndex needs any change. It 3090 // could happen that we have made a call out and thereby caused changes 3091 // to the _effectiveValues store on the current element. In that case 3092 // we would need to aquire new value for the index. 3093 // 3094 private EntryIndex CheckEntryIndex(EntryIndex entryIndex, int targetIndex) 3095 { 3096 uint effectiveValuesCount = EffectiveValuesCount; 3097 if (effectiveValuesCount > 0 && _effectiveValues.Length > entryIndex.Index) 3098 { 3099 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 3100 if (entry.PropertyIndex == targetIndex) 3101 { 3102 return new EntryIndex(entryIndex.Index); 3103 } 3104 } 3105 3106 return LookupEntry(targetIndex); 3107 } 3108 3109 // look for an entry that matches the given dp 3110 // return value has Found set to true if an entry is found 3111 // return value has Index set to the index of the found entry (if Found is true) 3112 // or the location to insert an entry for this dp (if Found is false) 3113 [FriendAccessAllowed] // Built into Base, also used by Framework. 3114 internal EntryIndex LookupEntry(int targetIndex) 3115 { 3116 int checkIndex; 3117 uint iLo = 0; 3118 uint iHi = EffectiveValuesCount; 3119 3120 if (iHi <= 0) 3121 { 3122 return new EntryIndex(0, false /* Found */); 3123 } 3124 3125 // Do a binary search to find the value 3126 while (iHi - iLo > 3) 3127 { 3128 uint iPv = (iHi + iLo) / 2; 3129 checkIndex = _effectiveValues[iPv].PropertyIndex; 3130 if (targetIndex == checkIndex) 3131 { 3132 return new EntryIndex(iPv); 3133 } 3134 if (targetIndex <= checkIndex) 3135 { 3136 iHi = iPv; 3137 } 3138 else 3139 { 3140 iLo = iPv + 1; 3141 } 3142 } 3143 3144 // Now we only have three values to search; switch to a linear search 3145 do 3146 { 3147 checkIndex = _effectiveValues[iLo].PropertyIndex; 3148 3149 if (checkIndex == targetIndex) 3150 { 3151 return new EntryIndex(iLo); 3152 } 3153 3154 if (checkIndex > targetIndex) 3155 { 3156 // we've gone past the targetIndex - return not found 3157 break; 3158 } 3159 3160 iLo++; 3161 } 3162 while (iLo < iHi); 3163 3164 return new EntryIndex(iLo, false /* Found */); 3165 } 3166 3167 // insert the given entry at the given index 3168 // this function assumes that entryIndex is at the right 3169 // location such that the resulting list remains sorted by EffectiveValueEntry.PropertyIndex 3170 private void InsertEntry(EffectiveValueEntry entry, uint entryIndex) 3171 { 3172 // For thread-safety, sealed DOs can't modify _effectiveValues. 3173 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 3174 3175 #if DEBUG 3176 EntryIndex debugIndex = LookupEntry(entry.PropertyIndex); 3177 Debug.Assert(!debugIndex.Found && debugIndex.Index == entryIndex, "Inserting duplicate"); 3178 #endif 3179 3180 if (CanModifyEffectiveValues == false) 3181 { 3182 throw new InvalidOperationException(SR.Get(SRID.LocalValueEnumerationInvalidated)); 3183 } 3184 3185 uint effectiveValuesCount = EffectiveValuesCount; 3186 if (effectiveValuesCount > 0) 3187 { 3188 if (_effectiveValues.Length == effectiveValuesCount) 3189 { 3190 int newSize = (int) (effectiveValuesCount * (IsInPropertyInitialization ? 2.0 : 1.2)); 3191 if (newSize == effectiveValuesCount) 3192 { 3193 newSize++; 3194 } 3195 3196 EffectiveValueEntry[] destEntries = new EffectiveValueEntry[newSize]; 3197 Array.Copy(_effectiveValues, 0, destEntries, 0, entryIndex); 3198 destEntries[entryIndex] = entry; 3199 Array.Copy(_effectiveValues, entryIndex, destEntries, entryIndex + 1, effectiveValuesCount - entryIndex); 3200 _effectiveValues = destEntries; 3201 } 3202 else 3203 { 3204 Array.Copy(_effectiveValues, entryIndex, _effectiveValues, entryIndex + 1, effectiveValuesCount - entryIndex); 3205 _effectiveValues[entryIndex] = entry; 3206 } 3207 } 3208 else 3209 { 3210 if (_effectiveValues == null) 3211 { 3212 _effectiveValues = new EffectiveValueEntry[EffectiveValuesInitialSize]; 3213 } 3214 _effectiveValues[0] = entry; 3215 } 3216 EffectiveValuesCount = effectiveValuesCount + 1; 3217 } 3218 3219 // remove the entry at the given index 3220 private void RemoveEntry(uint entryIndex, DependencyProperty dp) 3221 { 3222 // For thread-safety, sealed DOs can't modify _effectiveValues. 3223 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 3224 3225 if (CanModifyEffectiveValues == false) 3226 { 3227 throw new InvalidOperationException(SR.Get(SRID.LocalValueEnumerationInvalidated)); 3228 } 3229 3230 uint effectiveValuesCount = EffectiveValuesCount; 3231 Array.Copy(_effectiveValues, entryIndex + 1, _effectiveValues, entryIndex, (effectiveValuesCount - entryIndex) - 1); 3232 effectiveValuesCount--; 3233 EffectiveValuesCount = effectiveValuesCount; 3234 3235 // clear last entry 3236 _effectiveValues[effectiveValuesCount].Clear(); 3237 } 3238 3239 // 3240 // This property 3241 // 1. Finds the correct initial size for the _effectiveValues store on the current DependencyObject 3242 // 2. This is a performance optimization 3243 // 3244 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 3245 internal virtual int EffectiveValuesInitialSize 3246 { 3247 get { return 2; } 3248 } 3249 3250 internal void SetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry newEntry, EffectiveValueEntry oldEntry) 3251 { 3252 if (metadata != null && 3253 metadata.IsInherited && 3254 (newEntry.BaseValueSourceInternal != BaseValueSourceInternal.Inherited || 3255 newEntry.IsCoerced || newEntry.IsAnimated) && 3256 !IsSelfInheritanceParent) 3257 { 3258 SetIsSelfInheritanceParent(); 3259 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 3260 } 3261 3262 bool restoreMarker = false; 3263 3264 if (oldEntry.HasExpressionMarker && !newEntry.HasExpressionMarker) 3265 { 3266 BaseValueSourceInternal valueSource = newEntry.BaseValueSourceInternal; 3267 restoreMarker = (valueSource == BaseValueSourceInternal.ThemeStyle || 3268 valueSource == BaseValueSourceInternal.ThemeStyleTrigger || 3269 valueSource == BaseValueSourceInternal.Style || 3270 valueSource == BaseValueSourceInternal.TemplateTrigger || 3271 valueSource == BaseValueSourceInternal.StyleTrigger || 3272 valueSource == BaseValueSourceInternal.ParentTemplate || 3273 valueSource == BaseValueSourceInternal.ParentTemplateTrigger); 3274 } 3275 3276 if (restoreMarker) 3277 { 3278 newEntry.RestoreExpressionMarker(); 3279 } 3280 else if (oldEntry.IsExpression && oldEntry.ModifiedValue.ExpressionValue == Expression.NoValue) 3281 { 3282 // we now have a value for an expression that is "hiding" - save it 3283 // as the expression value 3284 newEntry.SetExpressionValue(newEntry.Value, oldEntry.ModifiedValue.BaseValue); 3285 } 3286 3287 #if DEBUG 3288 object baseValue; 3289 if (!newEntry.HasModifiers) 3290 { 3291 baseValue = newEntry.Value; 3292 } 3293 else 3294 { 3295 if (newEntry.IsCoercedWithCurrentValue) 3296 { 3297 baseValue = newEntry.ModifiedValue.CoercedValue; 3298 } 3299 else if (newEntry.IsExpression) 3300 { 3301 baseValue = newEntry.ModifiedValue.ExpressionValue; 3302 } 3303 else 3304 { 3305 baseValue = newEntry.ModifiedValue.BaseValue; 3306 } 3307 } 3308 3309 Debug.Assert(newEntry.IsDeferredReference == (baseValue is DeferredReference)); 3310 #endif 3311 3312 if (entryIndex.Found) 3313 { 3314 _effectiveValues[entryIndex.Index] = newEntry; 3315 } 3316 else 3317 { 3318 InsertEntry(newEntry, entryIndex.Index); 3319 if (metadata != null && metadata.IsInherited) 3320 { 3321 InheritableEffectiveValuesCount++; 3322 } 3323 } 3324 3325 Debug.Assert(dp == null || (dp.GlobalIndex == newEntry.PropertyIndex), "EffectiveValueEntry & DependencyProperty do not match"); 3326 } 3327 3328 // 3329 // This method 3330 // 1. Create a new EffectiveValueEntry for the given DP and inserts it into the EffectiveValues list 3331 // 3332 [FriendAccessAllowed] // Built into Base, also used by Core and Framework. 3333 internal void SetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, int targetIndex, PropertyMetadata metadata, object value, BaseValueSourceInternal valueSource) 3334 { 3335 Debug.Assert(value != DependencyProperty.UnsetValue, "Value to be set cannot be UnsetValue"); 3336 Debug.Assert(valueSource != BaseValueSourceInternal.Unknown, "ValueSource cannot be Unknown"); 3337 3338 // For thread-safety, sealed DOs can't modify _effectiveValues. 3339 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 3340 3341 if (metadata != null && 3342 metadata.IsInherited && 3343 valueSource != BaseValueSourceInternal.Inherited && 3344 !IsSelfInheritanceParent) 3345 { 3346 SetIsSelfInheritanceParent(); 3347 entryIndex = CheckEntryIndex(entryIndex, dp.GlobalIndex); 3348 } 3349 3350 EffectiveValueEntry entry; 3351 if (entryIndex.Found) 3352 { 3353 entry = _effectiveValues[entryIndex.Index]; 3354 } 3355 else 3356 { 3357 entry = new EffectiveValueEntry(); 3358 entry.PropertyIndex = targetIndex; 3359 InsertEntry(entry, entryIndex.Index); 3360 if (metadata != null && metadata.IsInherited) 3361 { 3362 InheritableEffectiveValuesCount++; 3363 } 3364 } 3365 3366 bool hasExpressionMarker = (value == ExpressionInAlternativeStore); 3367 3368 if (!hasExpressionMarker && 3369 entry.HasExpressionMarker && 3370 (valueSource == BaseValueSourceInternal.ThemeStyle || 3371 valueSource == BaseValueSourceInternal.ThemeStyleTrigger || 3372 valueSource == BaseValueSourceInternal.Style || 3373 valueSource == BaseValueSourceInternal.TemplateTrigger || 3374 valueSource == BaseValueSourceInternal.StyleTrigger || 3375 valueSource == BaseValueSourceInternal.ParentTemplate || 3376 valueSource == BaseValueSourceInternal.ParentTemplateTrigger)) 3377 { 3378 entry.BaseValueSourceInternal = valueSource; 3379 entry.SetExpressionValue(value, ExpressionInAlternativeStore); 3380 entry.ResetAnimatedValue(); 3381 entry.ResetCoercedValue(); 3382 } 3383 else if (entry.IsExpression && entry.ModifiedValue.ExpressionValue == Expression.NoValue) 3384 { 3385 // we now have a value for an expression that is "hiding" - save it 3386 // as the expression value 3387 entry.SetExpressionValue(value, entry.ModifiedValue.BaseValue); 3388 } 3389 else 3390 { 3391 Debug.Assert(entry.BaseValueSourceInternal != BaseValueSourceInternal.Local || valueSource == BaseValueSourceInternal.Local, 3392 "No one but another local value can stomp over an existing local value. The only way is to clear the entry"); 3393 3394 entry.BaseValueSourceInternal = valueSource; 3395 entry.ResetValue(value, hasExpressionMarker); 3396 } 3397 3398 Debug.Assert(dp == null || (dp.GlobalIndex == entry.PropertyIndex), "EffectiveValueEntry & DependencyProperty do not match"); 3399 _effectiveValues[entryIndex.Index] = entry; 3400 } 3401 3402 3403 // 3404 // This method 3405 // 1. Removes the entry if there is one with valueSource >= the specified 3406 // 3407 internal void UnsetEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata) 3408 { 3409 if (entryIndex.Found) 3410 { 3411 RemoveEntry(entryIndex.Index, dp); 3412 if (metadata != null && metadata.IsInherited) 3413 { 3414 InheritableEffectiveValuesCount--; 3415 } 3416 } 3417 } 3418 3419 // 3420 // This method 3421 // 1. Sets the expression on a ModifiedValue entry 3422 // 3423 private void SetExpressionValue(EntryIndex entryIndex, object value, object baseValue) 3424 { 3425 Debug.Assert(value != DependencyProperty.UnsetValue, "Value to be set cannot be UnsetValue"); 3426 Debug.Assert(baseValue != DependencyProperty.UnsetValue, "BaseValue to be set cannot be UnsetValue"); 3427 Debug.Assert(entryIndex.Found == true, "The baseValue for the expression should have been inserted prior to this and hence there should already been an entry for it."); 3428 3429 // For thread-safety, sealed DOs can't modify _effectiveValues. 3430 Debug.Assert(!DO_Sealed, "A Sealed DO cannot be modified"); 3431 3432 EffectiveValueEntry entry = _effectiveValues[entryIndex.Index]; 3433 3434 entry.SetExpressionValue(value, baseValue); 3435 entry.ResetAnimatedValue(); 3436 entry.ResetCoercedValue(); 3437 _effectiveValues[entryIndex.Index] = entry; 3438 } 3439 3440 /// <summary> 3441 /// Helper method to compare two DP values 3442 /// </summary> 3443 private bool Equals(DependencyProperty dp, object value1, object value2) 3444 { 3445 if (dp.IsValueType || dp.IsStringType) 3446 { 3447 // Use Object.Equals for Strings and ValueTypes 3448 return Object.Equals(value1, value2); 3449 } 3450 else 3451 { 3452 // Use Object.ReferenceEquals for all other ReferenceTypes 3453 return Object.ReferenceEquals(value1, value2); 3454 } 3455 } 3456 3457 #endregion EffectiveValues 3458 3459 #region InstanceData 3460 3461 // Specialized Type identification 3462 private DependencyObjectType _dType; 3463 3464 // For Freezable: 3465 // To save working set this object will initially reference a 3466 // single delegate/context. If a second object is added 3467 // of the same type, we will convert to a list/list, which will 3468 // be stored in _contextStorage. If the user ever adds an object of the 3469 // other type, we will create a HandlerContextStorage class, which _contextStorage 3470 // will then point at. 3471 3472 // For FrameworkContentElement/FrameworkElement: 3473 // This is the parent whose effective values store would contain the 3474 // value for the inheritable property on you. This change part of the 3475 // performance optimization around inheritable properties whereby you 3476 // wouldn't store the inheritable property on each and every node but 3477 // will hold it only the node that the property was actually set. 3478 internal object _contextStorage; 3479 3480 // The cache of effective values for this DependencyObject 3481 // This is an array sorted by DP.GlobalIndex. This ordering is 3482 // maintained via an insertion sort algorithm. 3483 private EffectiveValueEntry[] _effectiveValues; 3484 3485 // Stores: 3486 // Bits 0- 9 (0x000003FF): EffectiveValuesCount (0-1023) 3487 // Bits 10-18 (0x0007FC00): InheritableEffectiveValuesCount (0-511) 3488 // Bit 19 (0x00080000): CanModifyEffectiveValues, says if you can change the _effectiveValues cache on the current element. 3489 // Bit 20 (0x00100000): IsSelfInheritanceParent, says if all your inheritable property values are built into your effectiveValues store 3490 // Bit 21 (0x00200000): CanBeInheritanceContext, says if you can be an InheritanceContext for someone 3491 // Bit 22 (0x00400000): IsSealed: whether or not this DO is in readonly mode 3492 // Bit 23 (0x00800000): PropertyInitialization mode 3493 // Bit 24 (0x01000000): IsInheritanceContextSealed, says if you can change InheritanceContext 3494 // Bit 25 (0x02000000): Freezable_HasMultipleInheritanceContexts 3495 // Bit 26 (0x04000000): Freezable_UsingHandlerList 3496 // Bit 27 (0x08000000): Freezable_UsingContextList 3497 // Bit 28 (0x10000000): Freezable_UsingSingletonHandler 3498 // Bit 29 (0x20000000): Freezable_UsingSingletonContext 3499 // Bit 30 (0x40000000): Animatable_IsResourceInvalidationNecessary 3500 // Bit 31 (0x80000000): Animatable_HasAnimatedProperties 3501 3502 private UInt32 _packedData = 0; 3503 3504 #endregion InstanceData 3505 3506 #region StaticData 3507 3508 // special value in local store meaning that some alternative store (e.g. 3509 // the Framework's per-instance StyleData) is holding an Expression to 3510 // which we want to delegate SetValue. 3511 [FriendAccessAllowed] // Built into Base, also used by Framework. 3512 internal static readonly object ExpressionInAlternativeStore = new NamedObject("ExpressionInAlternativeStore"); 3513 3514 // callbacks used for alternative expression storage 3515 private static AlternativeExpressionStorageCallback _getExpressionCore; 3516 3517 #if VERBOSE_PROPERTY_EVENT 3518 internal static int ValidationCount; 3519 internal static int InvalidationCount; 3520 #endif 3521 3522 // This field stores the list of dependents in a FrugalMap. 3523 // The field is of type object for two reasons: 3524 // 1) FrugalMap is a struct, and generics over value types have perf issues 3525 // 2) so that we can have the default value of "null" mean Unset. 3526 internal static readonly UncommonField<object> DependentListMapField = new UncommonField<object>(); 3527 3528 // Optimization, to avoid calling FromSystemType too often 3529 internal static DependencyObjectType DType = DependencyObjectType.FromSystemTypeInternal(typeof(DependencyObject)); 3530 3531 private const int NestedOperationMaximum = 153; 3532 3533 #endregion StaticData 3534 } 3535 3536 /// <summary> Callback used by the "alternative Expression storage" feature </summary> 3537 /// <remarks> 3538 /// This should only be used by the Framework. It should not be used directly by users. 3539 /// </remarks> 3540 [FriendAccessAllowed] // Built into Base, also used by Framework. 3541 internal delegate Expression AlternativeExpressionStorageCallback(DependencyObject d, DependencyProperty dp, PropertyMetadata metadata); 3542 3543 [FriendAccessAllowed] // Built into Base, also used by Framework. 3544 internal enum UpdateResult 3545 { 3546 ValueChanged = 0x01, 3547 NotificationSent = 0x02, 3548 InheritedValueOverridden = 0x04, 3549 } 3550 3551 [FriendAccessAllowed] // Built into Base, also used by Framework. 3552 internal enum RequestFlags 3553 { 3554 FullyResolved = 0x00, 3555 AnimationBaseValue = 0x01, 3556 CoercionBaseValue = 0x02, 3557 DeferredReferences = 0x04, 3558 SkipDefault = 0x08, 3559 RawEntry = 0x10, 3560 } 3561 }
专注C#、C++。擅长WPF、WinForm、QT等技术。
研究ofd多年,开发了一些列产品。
技术交流QQ群:565438497。