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 }

 

posted @ 2017-12-18 20:51  源之缘-OFD先行者  阅读(3365)  评论(0编辑  收藏  举报
关注我