WPF 依赖属性源码 洞察微软如何实现DependencyProperty

依赖属性DependencyProperty是wpf最重要的一个类,理解该类如何实现对学习wpf帮助很大!

终于找到了该类的源码!仔细阅读源码,看看微软如何玩的花招!

   1 File: Base\System\Windows\DependencyProperty.cs
   2 Project: wpf\src\WindowsBase.csproj (WindowsBase)    
   3 using System;
   4 using System.Collections;
   5 using System.Collections.Generic;
   6 using System.Diagnostics;
   7 using System.Threading;
   8 using System.Globalization;
   9 using System.ComponentModel;
  10 using System.Windows.Markup;// For ValueSerializerAttribute
  11 using System.Windows.Threading; // For DispatcherObject
  12 using System.Security.Permissions; // For LinkDemand
  13 using MS.Utility;
  14 using MS.Internal.WindowsBase;
  15 using System.Reflection;   // for IsInstanceOfType
  16 using MS.Internal;
  17  
  18 #pragma warning disable 1634, 1691  // suppressing PreSharp warnings
  19  
  20 namespace System.Windows
  21 {
  22     /// <summary>
  23     ///     An attached dependency-based property
  24     /// </summary>
  25     [TypeConverter("System.Windows.Markup.DependencyPropertyConverter, PresentationFramework, Version=" + BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")]
  26     [ValueSerializer(typeof(DependencyPropertyValueSerializer))]
  27     public sealed class DependencyProperty
  28     {
  29         /// <summary>
  30         ///     Register a Dependency Property
  31         /// </summary>
  32         /// <param name="name">Name of property</param>
  33         /// <param name="propertyType">Type of the property</param>
  34         /// <param name="ownerType">Type that is registering the property</param>
  35         /// <returns>Dependency Property</returns>
  36         public static DependencyProperty Register(string name, Type propertyType, Type ownerType)
  37         {
  38             // Forwarding
  39             return Register(name, propertyType, ownerType, null, null);
  40         }
  41  
  42         /// <summary>
  43         ///     Register a Dependency Property
  44         /// </summary>
  45         /// <param name="name">Name of property</param>
  46         /// <param name="propertyType">Type of the property</param>
  47         /// <param name="ownerType">Type that is registering the property</param>
  48         /// <param name="typeMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  49         /// <returns>Dependency Property</returns>
  50         public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
  51         {
  52             // Forwarding
  53             return Register(name, propertyType, ownerType, typeMetadata, null);
  54         }
  55  
  56         /// <summary>
  57         ///     Register a Dependency Property
  58         /// </summary>
  59         /// <param name="name">Name of property</param>
  60         /// <param name="propertyType">Type of the property</param>
  61         /// <param name="ownerType">Type that is registering the property</param>
  62         /// <param name="typeMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
  63         /// <param name="validateValueCallback">Provides additional value validation outside automatic type validation</param>
  64         /// <returns>Dependency Property</returns>
  65         public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
  66         {
  67             RegisterParameterValidation(name, propertyType, ownerType);
  68  
  69             // Register an attached property
  70             PropertyMetadata defaultMetadata = null;
  71             if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
  72             {
  73                 defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
  74             }
  75  
  76             DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
  77  
  78             if (typeMetadata != null)
  79             {
  80                 // Apply type-specific metadata to owner type only
  81                 property.OverrideMetadata(ownerType, typeMetadata);
  82             }
  83  
  84             return property;
  85         }
  86  
  87         /// <summary>
  88         ///  Simple registration, metadata, validation, and a read-only property
  89         /// key.  Calling this version restricts the property such that it can
  90         /// only be set via the corresponding overload of DependencyObject.SetValue.
  91         /// </summary>
  92         public static DependencyPropertyKey RegisterReadOnly(
  93             string name,
  94             Type propertyType,
  95             Type ownerType,
  96             PropertyMetadata typeMetadata )
  97         {
  98             return RegisterReadOnly( name, propertyType, ownerType, typeMetadata, null );
  99         }
 100  
 101         /// <summary>
 102         ///  Simple registration, metadata, validation, and a read-only property
 103         /// key.  Calling this version restricts the property such that it can
 104         /// only be set via the corresponding overload of DependencyObject.SetValue.
 105         /// </summary>
 106         public static DependencyPropertyKey RegisterReadOnly(
 107             string name,
 108             Type propertyType,
 109             Type ownerType,
 110             PropertyMetadata typeMetadata,
 111             ValidateValueCallback validateValueCallback )
 112         {
 113             RegisterParameterValidation(name, propertyType, ownerType);
 114  
 115             PropertyMetadata defaultMetadata = null;
 116  
 117             if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
 118             {
 119                 defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
 120             }
 121             else
 122             {
 123                 defaultMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType);
 124             }
 125  
 126             //  We create a DependencyPropertyKey at this point with a null property
 127             // and set that in the _readOnlyKey field.  This is so the property is
 128             // marked as requiring a key immediately.  If something fails in the
 129             // initialization path, the property is still marked as needing a key.
 130             //  This is better than the alternative of creating and setting the key
 131             // later, because if that code fails the read-only property would not
 132             // be marked read-only.  The intent of this mildly convoluted code
 133             // is so we fail securely.
 134             DependencyPropertyKey authorizationKey = new DependencyPropertyKey(null); // No property yet, use null as placeholder.
 135  
 136             DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
 137  
 138             property._readOnlyKey = authorizationKey;
 139  
 140             authorizationKey.SetDependencyProperty(property);
 141  
 142             if (typeMetadata == null )
 143             {
 144                 // No metadata specified, generate one so we can specify the authorized key.
 145                 typeMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType);
 146             }
 147  
 148             // Authorize registering type for read-only access, create key.
 149             #pragma warning suppress 6506 // typeMetadata is never null, since we generate default metadata if none is provided.
 150  
 151             // Apply type-specific metadata to owner type only
 152             property.OverrideMetadata(ownerType, typeMetadata, authorizationKey);
 153  
 154             return authorizationKey;
 155         }
 156  
 157         /// <summary>
 158         ///  Simple registration, metadata, validation, and a read-only property
 159         /// key.  Calling this version restricts the property such that it can
 160         /// only be set via the corresponding overload of DependencyObject.SetValue.
 161         /// </summary>
 162         public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
 163         {
 164             return RegisterAttachedReadOnly( name, propertyType, ownerType, defaultMetadata, null );
 165         }
 166  
 167         /// <summary>
 168         ///  Simple registration, metadata, validation, and a read-only property
 169         /// key.  Calling this version restricts the property such that it can
 170         /// only be set via the corresponding overload of DependencyObject.SetValue.
 171         /// </summary>
 172         public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
 173         {
 174             RegisterParameterValidation(name, propertyType, ownerType);
 175  
 176             // Establish default metadata for all types, if none is provided
 177             if (defaultMetadata == null)
 178             {
 179                 defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
 180             }
 181  
 182             //  We create a DependencyPropertyKey at this point with a null property
 183             // and set that in the _readOnlyKey field.  This is so the property is
 184             // marked as requiring a key immediately.  If something fails in the
 185             // initialization path, the property is still marked as needing a key.
 186             //  This is better than the alternative of creating and setting the key
 187             // later, because if that code fails the read-only property would not
 188             // be marked read-only.  The intent of this mildly convoluted code
 189             // is so we fail securely.
 190             DependencyPropertyKey authorizedKey = new DependencyPropertyKey(null);
 191  
 192             DependencyProperty property = RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback);
 193  
 194             property._readOnlyKey = authorizedKey;
 195  
 196             authorizedKey.SetDependencyProperty(property);
 197  
 198             return authorizedKey;
 199         }
 200  
 201         /// <summary>
 202         ///     Register an attached Dependency Property
 203         /// </summary>
 204         /// <param name="name">Name of property</param>
 205         /// <param name="propertyType">Type of the property</param>
 206         /// <param name="ownerType">Type that is registering the property</param>
 207         /// <returns>Dependency Property</returns>
 208         public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType)
 209         {
 210             // Forwarding
 211             return RegisterAttached(name, propertyType, ownerType, null, null );
 212         }
 213  
 214         /// <summary>
 215         ///     Register an attached Dependency Property
 216         /// </summary>
 217         /// <param name="name">Name of property</param>
 218         /// <param name="propertyType">Type of the property</param>
 219         /// <param name="ownerType">Type that is registering the property</param>
 220         /// <param name="defaultMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
 221         /// <returns>Dependency Property</returns>
 222         public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
 223         {
 224             // Forwarding
 225             return RegisterAttached(name, propertyType, ownerType, defaultMetadata, null );
 226         }
 227  
 228         /// <summary>
 229         ///     Register an attached Dependency Property
 230         /// </summary>
 231         /// <param name="name">Name of property</param>
 232         /// <param name="propertyType">Type of the property</param>
 233         /// <param name="ownerType">Type that is registering the property</param>
 234         /// <param name="defaultMetadata">Metadata to use if current type doesn't specify type-specific metadata</param>
 235         /// <param name="validateValueCallback">Provides additional value validation outside automatic type validation</param>
 236         /// <returns>Dependency Property</returns>
 237         public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
 238         {
 239             RegisterParameterValidation(name, propertyType, ownerType);
 240  
 241             return RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback );
 242         }
 243  
 244         private static void RegisterParameterValidation(string name, Type propertyType, Type ownerType)
 245         {
 246             if (name == null)
 247             {
 248                 throw new ArgumentNullException("name");
 249             }
 250  
 251             if (name.Length == 0)
 252             {
 253                 throw new ArgumentException(SR.Get(SRID.StringEmpty), "name");
 254             }
 255  
 256             if (ownerType == null)
 257             {
 258                 throw new ArgumentNullException("ownerType");
 259             }
 260  
 261             if (propertyType == null)
 262             {
 263                 throw new ArgumentNullException("propertyType");
 264             }
 265         }
 266  
 267         private static DependencyProperty RegisterCommon(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
 268         {
 269             FromNameKey key = new FromNameKey(name, ownerType);
 270             lock (Synchronized)
 271             {
 272                 if (PropertyFromName.Contains(key))
 273                 {
 274                     throw new ArgumentException(SR.Get(SRID.PropertyAlreadyRegistered, name, ownerType.Name));
 275                 }
 276             }
 277  
 278             // Establish default metadata for all types, if none is provided
 279             if (defaultMetadata == null)
 280             {
 281                 defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
 282             }
 283             else // Metadata object is provided.
 284             {
 285                 // If the defaultValue wasn't specified auto generate one
 286                 if (!defaultMetadata.DefaultValueWasSet())
 287                 {
 288                     defaultMetadata.DefaultValue = AutoGenerateDefaultValue(propertyType);
 289                 }
 290  
 291                 ValidateMetadataDefaultValue( defaultMetadata, propertyType, name, validateValueCallback );
 292             }
 293  
 294             // Create property
 295             DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
 296  
 297             // Seal (null means being used for default metadata, calls OnApply)
 298             defaultMetadata.Seal(dp, null);
 299  
 300             if (defaultMetadata.IsInherited)
 301             {
 302                 dp._packedData |= Flags.IsPotentiallyInherited;
 303             }
 304  
 305             if (defaultMetadata.UsingDefaultValueFactory)
 306             {
 307                 dp._packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
 308             }
 309  
 310  
 311             // Map owner type to this property
 312             // Build key
 313             lock (Synchronized)
 314             {
 315                 PropertyFromName[key] = dp;
 316             }
 317  
 318  
 319             if( TraceDependencyProperty.IsEnabled )
 320             {
 321                 TraceDependencyProperty.TraceActivityItem(
 322                     TraceDependencyProperty.Register,
 323                     dp,
 324                     dp.OwnerType );
 325             }
 326  
 327  
 328             return dp;
 329         }
 330  
 331         private static object AutoGenerateDefaultValue(
 332             Type propertyType)
 333         {
 334             // Default per-type metadata not provided, create
 335             object defaultValue = null;
 336  
 337             // Auto-assigned default value
 338             if (propertyType.IsValueType)
 339             {
 340                 // Value-types have default-constructed type default values
 341                 defaultValue = Activator.CreateInstance(propertyType);
 342             }
 343  
 344             return defaultValue;
 345         }
 346  
 347         private static PropertyMetadata AutoGeneratePropertyMetadata(
 348             Type propertyType,
 349             ValidateValueCallback validateValueCallback,
 350             string name,
 351             Type ownerType)
 352         {
 353             // Default per-type metadata not provided, create
 354             object defaultValue = AutoGenerateDefaultValue(propertyType);
 355  
 356             // If a validator is passed in, see if the default value makes sense.
 357             if ( validateValueCallback != null &&
 358                 !validateValueCallback(defaultValue))
 359             {
 360                 // Didn't work - require the caller to specify one.
 361                 throw new ArgumentException(SR.Get(SRID.DefaultValueAutoAssignFailed, name, ownerType.Name));
 362             }
 363  
 364             return new PropertyMetadata(defaultValue);
 365         }
 366  
 367         // Validate the default value in the given metadata
 368         private static void ValidateMetadataDefaultValue(
 369             PropertyMetadata defaultMetadata,
 370             Type propertyType,
 371             string propertyName,
 372             ValidateValueCallback validateValueCallback )
 373         {
 374             // If we are registered to use the DefaultValue factory we can
 375             // not validate the DefaultValue at registration time, so we
 376             // early exit.
 377             if (defaultMetadata.UsingDefaultValueFactory)
 378             {
 379                 return;
 380             }
 381  
 382             ValidateDefaultValueCommon(defaultMetadata.DefaultValue, propertyType,
 383                 propertyName, validateValueCallback, /*checkThreadAffinity = */ true);
 384         }
 385  
 386         // Validate the given default value, used by PropertyMetadata.GetDefaultValue()
 387         // when the DefaultValue factory is used.
 388         // These default values are allowed to have thread-affinity.
 389         internal void ValidateFactoryDefaultValue(object defaultValue)
 390         {
 391             ValidateDefaultValueCommon(defaultValue, PropertyType, Name, ValidateValueCallback, false);
 392         }
 393  
 394         private static void ValidateDefaultValueCommon(
 395             object defaultValue,
 396             Type propertyType,
 397             string propertyName,
 398             ValidateValueCallback validateValueCallback,
 399             bool checkThreadAffinity)
 400         {
 401             // Ensure default value is the correct type
 402             if (!IsValidType(defaultValue, propertyType))
 403             {
 404                 throw new ArgumentException(SR.Get(SRID.DefaultValuePropertyTypeMismatch, propertyName));
 405             }
 406  
 407             // An Expression used as default value won't behave as expected since
 408             //  it doesn't get evaluated.  We explicitly fail it here.
 409             if (defaultValue is Expression )
 410             {
 411                 throw new ArgumentException(SR.Get(SRID.DefaultValueMayNotBeExpression));
 412             }
 413  
 414             if (checkThreadAffinity)
 415             {
 416                 // If the default value is a DispatcherObject with thread affinity
 417                 // we cannot accept it as a default value. If it implements ISealable
 418                 // we attempt to seal it; if not we throw  an exception. Types not
 419                 // deriving from DispatcherObject are allowed - it is up to the user to
 420                 // make any custom types free-threaded.
 421  
 422                 DispatcherObject dispatcherObject = defaultValue as DispatcherObject;
 423  
 424                 if (dispatcherObject != null && dispatcherObject.Dispatcher != null)
 425                 {
 426                     // Try to make the DispatcherObject free-threaded if it's an
 427                     // ISealable.
 428  
 429                     ISealable valueAsISealable = dispatcherObject as ISealable;
 430  
 431                     if (valueAsISealable != null && valueAsISealable.CanSeal)
 432                     {
 433                         Invariant.Assert (!valueAsISealable.IsSealed,
 434                                "A Sealed ISealable must not have dispatcher affinity");
 435  
 436                         valueAsISealable.Seal();
 437  
 438                         Invariant.Assert(dispatcherObject.Dispatcher == null,
 439                             "ISealable.Seal() failed after ISealable.CanSeal returned true");
 440                     }
 441                     else
 442                     {
 443                         throw new ArgumentException(SR.Get(SRID.DefaultValueMustBeFreeThreaded, propertyName));
 444                     }
 445                 }
 446             }
 447  
 448  
 449             // After checking for correct type, check default value against
 450             //  validator (when one is given)
 451             if ( validateValueCallback != null &&
 452                 !validateValueCallback(defaultValue))
 453             {
 454                 throw new ArgumentException(SR.Get(SRID.DefaultValueInvalid, propertyName));
 455             }
 456         }
 457  
 458  
 459         /// <summary>
 460         ///     Parameter validation for OverrideMetadata, includes code to force
 461         /// all base classes of "forType" to register their metadata so we know
 462         /// what we are overriding.
 463         /// </summary>
 464         private void SetupOverrideMetadata(
 465                 Type forType,
 466                 PropertyMetadata typeMetadata,
 467             out DependencyObjectType dType,
 468             out PropertyMetadata baseMetadata )
 469         {
 470             if (forType == null)
 471             {
 472                 throw new ArgumentNullException("forType");
 473             }
 474  
 475             if (typeMetadata == null)
 476             {
 477                 throw new ArgumentNullException("typeMetadata");
 478             }
 479  
 480             if (typeMetadata.Sealed)
 481             {
 482                 throw new ArgumentException(SR.Get(SRID.TypeMetadataAlreadyInUse));
 483             }
 484  
 485             if (!typeof(DependencyObject).IsAssignableFrom(forType))
 486             {
 487                 throw new ArgumentException(SR.Get(SRID.TypeMustBeDependencyObjectDerived, forType.Name));
 488             }
 489  
 490             // Ensure default value is a correct value (if it was supplied,
 491             // otherwise, the default value will be taken from the base metadata
 492             // which was already validated)
 493             if (typeMetadata.IsDefaultValueModified)
 494             {
 495                 // Will throw ArgumentException if fails.
 496                 ValidateMetadataDefaultValue( typeMetadata, PropertyType, Name, ValidateValueCallback );
 497             }
 498  
 499             // Force all base classes to register their metadata
 500             dType = DependencyObjectType.FromSystemType(forType);
 501  
 502             // Get metadata for the base type
 503             baseMetadata = GetMetadata(dType.BaseType);
 504  
 505             // Make sure overriding metadata is the same type or derived type of
 506             // the base metadata
 507             if (!baseMetadata.GetType().IsAssignableFrom(typeMetadata.GetType()))
 508             {
 509                 throw new ArgumentException(SR.Get(SRID.OverridingMetadataDoesNotMatchBaseMetadataType));
 510             }
 511         }
 512  
 513  
 514         /// <summary>
 515         ///     Supply metadata for given type & run static constructors if needed.
 516         /// </summary>
 517         /// <remarks>
 518         ///     The supplied metadata will be merged with the type's base
 519         ///     metadata
 520         /// </remarks>
 521         public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
 522         {
 523             DependencyObjectType dType;
 524             PropertyMetadata baseMetadata;
 525  
 526             SetupOverrideMetadata(forType, typeMetadata, out dType, out baseMetadata);
 527  
 528             if (ReadOnly)
 529             {
 530                 // Readonly and no DependencyPropertyKey - not allowed.
 531                 throw new InvalidOperationException(SR.Get(SRID.ReadOnlyOverrideNotAllowed, Name));
 532             }
 533  
 534             ProcessOverrideMetadata(forType, typeMetadata, dType, baseMetadata);
 535         }
 536  
 537         /// <summary>
 538         ///     Supply metadata for a given type, overriding a property that is
 539         /// read-only.  If property is not read only, tells user to use the Plain
 540         /// Jane OverrideMetadata instead.
 541         /// </summary>
 542         public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata, DependencyPropertyKey key)
 543         {
 544             DependencyObjectType dType;
 545             PropertyMetadata baseMetadata;
 546  
 547             SetupOverrideMetadata(forType, typeMetadata, out dType, out baseMetadata);
 548  
 549             if (key == null)
 550             {
 551                 throw new ArgumentNullException("key");
 552             }
 553  
 554             if (ReadOnly)
 555             {
 556                 // If the property is read-only, the key must match this property
 557                 //  and the key must match that in the base metadata.
 558  
 559                 if (key.DependencyProperty != this)
 560                 {
 561                     throw new ArgumentException(SR.Get(SRID.ReadOnlyOverrideKeyNotAuthorized, Name));
 562                 }
 563  
 564                 VerifyReadOnlyKey(key);
 565             }
 566             else
 567             {
 568                 throw new InvalidOperationException(SR.Get(SRID.PropertyNotReadOnly));
 569             }
 570  
 571             // Either the property doesn't require a key, or the key match was
 572             //  successful.  Proceed with the metadata override.
 573             ProcessOverrideMetadata(forType, typeMetadata, dType, baseMetadata);
 574         }
 575  
 576         /// <summary>
 577         ///     After parameters have been validated for OverrideMetadata, this
 578         /// method is called to actually update the data structures.
 579         /// </summary>
 580         private void ProcessOverrideMetadata(
 581             Type forType,
 582             PropertyMetadata typeMetadata,
 583             DependencyObjectType dType,
 584             PropertyMetadata baseMetadata)
 585         {
 586             // Store per-Type metadata for this property. Locks only on Write.
 587             // Datastructure guaranteed to be valid for non-locking readers
 588             lock (Synchronized)
 589             {
 590                 if (DependencyProperty.UnsetValue == _metadataMap[dType.Id])
 591                 {
 592                     _metadataMap[dType.Id] = typeMetadata;
 593                 }
 594                 else
 595                 {
 596                     throw new ArgumentException(SR.Get(SRID.TypeMetadataAlreadyRegistered, forType.Name));
 597                 }
 598            }
 599  
 600             // Merge base's metadata into this metadata
 601             // CALLBACK
 602             typeMetadata.InvokeMerge(baseMetadata, this);
 603  
 604             // Type metadata may no longer change (calls OnApply)
 605             typeMetadata.Seal(this, forType);
 606  
 607             if (typeMetadata.IsInherited)
 608             {
 609                 _packedData |= Flags.IsPotentiallyInherited;
 610             }
 611  
 612             if (typeMetadata.DefaultValueWasSet() && (typeMetadata.DefaultValue != DefaultMetadata.DefaultValue))
 613             {
 614                 _packedData |= Flags.IsDefaultValueChanged;
 615             }
 616  
 617             if (typeMetadata.UsingDefaultValueFactory)
 618             {
 619                 _packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
 620             }
 621         }
 622  
 623  
 624         [FriendAccessAllowed]   // Built into Base, also used by Core & Framework.
 625         internal object GetDefaultValue(DependencyObjectType dependencyObjectType)
 626         {
 627             if (!IsDefaultValueChanged)
 628             {
 629                 return DefaultMetadata.DefaultValue;
 630             }
 631  
 632             return GetMetadata(dependencyObjectType).DefaultValue;
 633         }
 634  
 635         [FriendAccessAllowed]   // Built into Base, also used by Core & Framework.
 636         internal object GetDefaultValue(Type forType)
 637         {
 638             if (!IsDefaultValueChanged)
 639             {
 640                 return DefaultMetadata.DefaultValue;
 641             }
 642  
 643             return GetMetadata(DependencyObjectType.FromSystemTypeInternal(forType)).DefaultValue;
 644         }
 645  
 646         /// <summary>
 647         ///     Retrieve metadata for a provided type
 648         /// </summary>
 649         /// <param name="forType">Type to get metadata</param>
 650         /// <returns>Property metadata</returns>
 651         public PropertyMetadata GetMetadata(Type forType)
 652         {
 653             if (forType != null)
 654             {
 655                 return GetMetadata(DependencyObjectType.FromSystemType(forType));
 656             }
 657             throw new ArgumentNullException("forType");
 658         }
 659  
 660         /// <summary>
 661         ///     Retrieve metadata for a provided DependencyObject
 662         /// </summary>
 663         /// <param name="dependencyObject">DependencyObject to get metadata</param>
 664         /// <returns>Property metadata</returns>
 665         public PropertyMetadata GetMetadata(DependencyObject dependencyObject)
 666         {
 667             if (dependencyObject != null)
 668             {
 669                 return GetMetadata(dependencyObject.DependencyObjectType);
 670             }
 671             throw new ArgumentNullException("dependencyObject");
 672         }
 673  
 674         /// <summary>
 675         /// Reteive metadata for a DependencyObject type described by the
 676         /// given DependencyObjectType
 677         /// </summary>
 678         //CASRemoval:[StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey = BuildInfo.WCP_PUBLIC_KEY_STRING)]
 679         public PropertyMetadata GetMetadata(DependencyObjectType dependencyObjectType)
 680         {
 681             // All static constructors for this DType and all base types have already
 682             // been run. If no overriden metadata was provided, then look up base types.
 683             // If no metadata found on base types, then return default
 684  
 685             if (null != dependencyObjectType)
 686             {
 687                 // Do we in fact have any overrides at all?
 688                 int index = _metadataMap.Count - 1;
 689                 int Id;
 690                 object value;
 691  
 692                 if (index < 0)
 693                 {
 694                     // No overrides or it's the base class
 695                     return _defaultMetadata;
 696                 }
 697                 else if (index == 0)
 698                 {
 699                     // Only 1 override
 700                     _metadataMap.GetKeyValuePair(index, out Id, out value);
 701  
 702                     // If there is overriden metadata, then there is a base class with
 703                     // lower or equal Id of this class, or this class is already a base class
 704                     // of the overridden one. Therefore dependencyObjectType won't ever
 705                     // become null before we exit the while loop
 706                     while (dependencyObjectType.Id > Id)
 707                     {
 708                         dependencyObjectType = dependencyObjectType.BaseType;
 709                     }
 710  
 711                     if (Id == dependencyObjectType.Id)
 712                     {
 713                         // Return the override
 714                         return (PropertyMetadata)value;
 715                     }
 716                     // Return default metadata
 717                 }
 718                 else
 719                 {
 720                     // We have more than 1 override for this class, so we will have to loop through
 721                     // both the overrides and the class Id
 722                     if (0 != dependencyObjectType.Id)
 723                     {
 724                         do
 725                         {
 726                             // Get the Id of the most derived class with overridden metadata
 727                             _metadataMap.GetKeyValuePair(index, out Id, out value);
 728                             --index;
 729  
 730                             // If the Id of this class is less than the override, then look for an override
 731                             // with an equal or lower Id until we run out of overrides
 732                             while ((dependencyObjectType.Id < Id) && (index >= 0))
 733                             {
 734                                 _metadataMap.GetKeyValuePair(index, out Id, out value);
 735                                 --index;
 736                             }
 737  
 738                             // If there is overriden metadata, then there is a base class with
 739                             // lower or equal Id of this class, or this class is already a base class
 740                             // of the overridden one. Therefore dependencyObjectType won't ever
 741                             // become null before we exit the while loop
 742                             while (dependencyObjectType.Id > Id)
 743                             {
 744                                 dependencyObjectType = dependencyObjectType.BaseType;
 745                             }
 746  
 747                             if (Id == dependencyObjectType.Id)
 748                             {
 749                                 // Return the override
 750                                 return (PropertyMetadata)value;
 751                             }
 752                         }
 753                         while (index >= 0);
 754                     }
 755                 }
 756             }
 757             return _defaultMetadata;
 758         }
 759  
 760  
 761         /// <summary>
 762         ///     Associate another owner type with this property
 763         /// </summary>
 764         /// <remarks>
 765         ///     The owner type is used when resolving a property by name (<see cref="FromName"/>)
 766         /// </remarks>
 767         /// <param name="ownerType">Additional owner type</param>
 768         /// <returns>This property</returns>
 769         public DependencyProperty AddOwner(Type ownerType)
 770         {
 771             // Forwarding
 772             return AddOwner(ownerType, null);
 773         }
 774  
 775         /// <summary>
 776         ///     Associate another owner type with this property
 777         /// </summary>
 778         /// <remarks>
 779         ///     The owner type is used when resolving a property by name (<see cref="FromName"/>)
 780         /// </remarks>
 781         /// <param name="ownerType">Additional owner type</param>
 782         /// <param name="typeMetadata">Optional type metadata to override on owner's behalf</param>
 783         /// <returns>This property</returns>
 784         public DependencyProperty AddOwner(Type ownerType, PropertyMetadata typeMetadata)
 785         {
 786             if (ownerType == null)
 787             {
 788                 throw new ArgumentNullException("ownerType");
 789             }
 790  
 791             // Map owner type to this property
 792             // Build key
 793             FromNameKey key = new FromNameKey(Name, ownerType);
 794  
 795             lock (Synchronized)
 796             {
 797                 if (PropertyFromName.Contains(key))
 798                 {
 799                     throw new ArgumentException(SR.Get(SRID.PropertyAlreadyRegistered, Name, ownerType.Name));
 800                 }
 801             }
 802  
 803             if (typeMetadata != null)
 804             {
 805                 OverrideMetadata(ownerType, typeMetadata);
 806             }
 807  
 808  
 809             lock (Synchronized)
 810             {
 811                 PropertyFromName[key] = this;
 812             }
 813  
 814  
 815             return this;
 816         }
 817  
 818  
 819         /// <summary>
 820         ///     Name of the property
 821         /// </summary>
 822         public string Name
 823         {
 824             get { return _name; }
 825         }
 826  
 827         /// <summary>
 828         ///     Type of the property
 829         /// </summary>
 830         public Type PropertyType
 831         {
 832             get { return _propertyType; }
 833         }
 834  
 835         /// <summary>
 836         ///     Owning type of the property
 837         /// </summary>
 838         public Type OwnerType
 839         {
 840             get { return _ownerType; }
 841         }
 842  
 843         /// <summary>
 844         ///     Default metadata for the property
 845         /// </summary>
 846         public PropertyMetadata DefaultMetadata
 847         {
 848             get { return _defaultMetadata; }
 849         }
 850  
 851         /// <summary>
 852         ///     Value validation callback
 853         /// </summary>
 854         public ValidateValueCallback ValidateValueCallback
 855         {
 856             get { return _validateValueCallback; }
 857         }
 858  
 859         /// <summary>
 860         ///     Zero-based globally unique index of the property
 861         /// </summary>
 862         public int GlobalIndex
 863         {
 864             get { return (int) (_packedData & Flags.GlobalIndexMask); }
 865         }
 866  
 867         internal bool IsObjectType
 868         {
 869             get { return (_packedData & Flags.IsObjectType) != 0; }
 870         }
 871  
 872         internal bool IsValueType
 873         {
 874             get { return (_packedData & Flags.IsValueType) != 0; }
 875         }
 876  
 877         internal bool IsFreezableType
 878         {
 879             get { return (_packedData & Flags.IsFreezableType) != 0; }
 880         }
 881  
 882         internal bool IsStringType
 883         {
 884             get { return (_packedData & Flags.IsStringType) != 0; }
 885         }
 886  
 887         internal bool IsPotentiallyInherited
 888         {
 889             get { return (_packedData & Flags.IsPotentiallyInherited) != 0; }
 890         }
 891  
 892         internal bool IsDefaultValueChanged
 893         {
 894             get { return (_packedData & Flags.IsDefaultValueChanged) != 0; }
 895         }
 896  
 897         internal bool IsPotentiallyUsingDefaultValueFactory
 898         {
 899             get { return (_packedData & Flags.IsPotentiallyUsingDefaultValueFactory) != 0; }
 900         }
 901  
 902         /// <summary>
 903         ///     Serves as a hash function for a particular type, suitable for use in
 904         ///     hashing algorithms and data structures like a hash table
 905         /// </summary>
 906         /// <returns>The DependencyProperty's GlobalIndex</returns>
 907         public override int GetHashCode()
 908         {
 909             return GlobalIndex;
 910         }
 911  
 912         /// <summary>
 913         ///     Used to determine if given value is appropriate for the type of the property
 914         /// </summary>
 915         /// <param name="value">Value to check</param>
 916         /// <returns>true if value matches property type</returns>
 917         public bool IsValidType(object value)
 918         {
 919             return IsValidType(value, PropertyType);
 920         }
 921  
 922  
 923         /// <summary>
 924         ///     Used to determine if given value is appropriate for the type of the property
 925         ///     and the range of values (as specified via the ValidateValueCallback) within that type
 926         /// </summary>
 927         /// <param name="value">Value to check</param>
 928         /// <returns>true if value is appropriate</returns>
 929         public bool IsValidValue(object value)
 930         {
 931             if (!IsValidType(value, PropertyType))
 932             {
 933                 return false;
 934             }
 935  
 936             if (ValidateValueCallback != null)
 937             {
 938                 // CALLBACK
 939                 return ValidateValueCallback(value);
 940             }
 941  
 942             return true;
 943         }
 944  
 945         /// <summary>
 946         ///     Set/Value value disabling
 947         /// </summary>
 948         public bool ReadOnly
 949         {
 950             get
 951             {
 952                 return (_readOnlyKey != null);
 953             }
 954         }
 955  
 956         /// <summary>
 957         ///     Returns the DependencyPropertyKey associated with this DP.
 958         /// </summary>
 959         internal DependencyPropertyKey DependencyPropertyKey
 960         {
 961             get
 962             {
 963                 return _readOnlyKey;
 964             }
 965         }
 966  
 967         internal void VerifyReadOnlyKey( DependencyPropertyKey candidateKey )
 968         {
 969             Debug.Assert( ReadOnly, "Why are we trying to validate read-only key on a property that is not read-only?");
 970  
 971             if (_readOnlyKey != candidateKey)
 972             {
 973                 throw new ArgumentException(SR.Get(SRID.ReadOnlyKeyNotAuthorized));
 974             }
 975         }
 976  
 977         /// <summary>
 978         ///     Internal version of IsValidValue that bypasses IsValidType check;
 979         ///     Called from SetValueInternal
 980         /// </summary>
 981         /// <param name="value">Value to check</param>
 982         /// <returns>true if value is appropriate</returns>
 983         internal bool IsValidValueInternal(object value)
 984         {
 985             if (ValidateValueCallback != null)
 986             {
 987                 // CALLBACK
 988                 return ValidateValueCallback(value);
 989             }
 990  
 991             return true;
 992         }
 993  
 994         /// <summary>
 995         ///     Find a property from name
 996         /// </summary>
 997         /// <remarks>
 998         ///     Search includes base classes of the provided type as well
 999         /// </remarks>
1000         /// <param name="name">Name of the property</param>
1001         /// <param name="ownerType">Owner type of the property</param>
1002         /// <returns>Dependency property</returns>
1003         [FriendAccessAllowed]   // Built into Base, also used by Framework.
1004         internal static DependencyProperty FromName(string name, Type ownerType)
1005         {
1006             DependencyProperty dp = null;
1007  
1008             if (name != null)
1009             {
1010                 if (ownerType != null)
1011                 {
1012                     FromNameKey key = new FromNameKey(name, ownerType);
1013  
1014                     while ((dp == null) && (ownerType != null))
1015                     {
1016                         // Ensure static constructor of type has run
1017                         MS.Internal.WindowsBase.SecurityHelper.RunClassConstructor(ownerType);
1018  
1019                         // Locate property
1020                         key.UpdateNameKey(ownerType);
1021  
1022                         lock (Synchronized)
1023                         {
1024                             dp = (DependencyProperty)PropertyFromName[key];
1025                         }
1026  
1027                         ownerType = ownerType.BaseType;
1028                     }
1029                 }
1030                 else
1031                 {
1032                     throw new ArgumentNullException("ownerType");
1033                 }
1034             }
1035             else
1036             {
1037                 throw new ArgumentNullException("name");
1038             }
1039             return dp;
1040         }
1041  
1042  
1043         /// <summary>
1044         ///    String representation
1045         /// </summary>
1046         public override string ToString()
1047         {
1048             return _name;
1049         }
1050  
1051  
1052         internal static bool IsValidType(object value, Type propertyType)
1053         {
1054             if (value == null)
1055             {
1056                 // Null values are invalid for value-types
1057                 if (propertyType.IsValueType &&
1058                     !(propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == NullableType))
1059                 {
1060                     return false;
1061                 }
1062             }
1063             else
1064             {
1065                 // Non-null default value, ensure its the correct type
1066                 if (!propertyType.IsInstanceOfType(value))
1067                 {
1068                     return false;
1069                 }
1070             }
1071  
1072             return true;
1073         }
1074  
1075         private class FromNameKey
1076         {
1077             public FromNameKey(string name, Type ownerType)
1078             {
1079                 _name = name;
1080                 _ownerType = ownerType;
1081  
1082                 _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
1083             }
1084  
1085             public void UpdateNameKey(Type ownerType)
1086             {
1087                 _ownerType = ownerType;
1088  
1089                 _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
1090             }
1091  
1092             public override int GetHashCode()
1093             {
1094                 return _hashCode;
1095             }
1096  
1097             public override bool Equals(object o)
1098             {
1099                 if ((o != null) && (o is FromNameKey))
1100                 {
1101                     return Equals((FromNameKey)o);
1102                 }
1103                 else
1104                 {
1105                     return false;
1106                 }
1107             }
1108  
1109             public bool Equals(FromNameKey key)
1110             {
1111                 return (_name.Equals(key._name) && (_ownerType == key._ownerType));
1112             }
1113  
1114             private string _name;
1115             private Type _ownerType;
1116  
1117             private int _hashCode;
1118         }
1119  
1120  
1121         private DependencyProperty(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
1122         {
1123             _name = name;
1124             _propertyType = propertyType;
1125             _ownerType = ownerType;
1126             _defaultMetadata = defaultMetadata;
1127             _validateValueCallback = validateValueCallback;
1128  
1129             Flags packedData;
1130             lock (Synchronized)
1131             {
1132                 packedData = (Flags) GetUniqueGlobalIndex(ownerType, name);
1133  
1134                 RegisteredPropertyList.Add(this);
1135             }
1136  
1137             if (propertyType.IsValueType)
1138             {
1139                 packedData |= Flags.IsValueType;
1140             }
1141  
1142             if (propertyType == typeof(object))
1143             {
1144                 packedData |= Flags.IsObjectType;
1145             }
1146  
1147             if (typeof(Freezable).IsAssignableFrom(propertyType))
1148             {
1149                 packedData |= Flags.IsFreezableType;
1150             }
1151  
1152             if (propertyType == typeof(string))
1153             {
1154                 packedData |= Flags.IsStringType;
1155             }
1156  
1157             _packedData = packedData;
1158         }
1159  
1160         // Synchronized: Covered by DependencyProperty.Synchronized
1161         internal static int GetUniqueGlobalIndex(Type ownerType, string name)
1162         {
1163             // Prevent GlobalIndex from overflow. DependencyProperties are meant to be static members and are to be registered
1164             // only via static constructors. However there is no cheap way of ensuring this, without having to do a stack walk. Hence
1165             // concievably people could register DependencyProperties via instance methods and therefore cause the GlobalIndex to
1166             // overflow. This check will explicitly catch this error, instead of silently malfuntioning.
1167             if (GlobalIndexCount >= (int)Flags.GlobalIndexMask)
1168             {
1169                 if (ownerType != null)
1170                 {
1171                     throw new InvalidOperationException(SR.Get(SRID.TooManyDependencyProperties, ownerType.Name + "." + name));
1172                 }
1173                 else
1174                 {
1175                     throw new InvalidOperationException(SR.Get(SRID.TooManyDependencyProperties, "ConstantProperty"));
1176                 }
1177             }
1178  
1179             // Covered by Synchronized by caller
1180             return GlobalIndexCount++;
1181         }
1182  
1183         /// <summary>
1184         /// This is the callback designers use to participate in the computation of property
1185         /// values at design time. Eg. Even if the author sets Visibility to Hidden, the designer
1186         /// wants to coerce the value to Visible at design time so that the element doesn't
1187         /// disappear from the design surface.
1188         /// </summary>
1189         internal CoerceValueCallback DesignerCoerceValueCallback
1190         {
1191             get {  return _designerCoerceValueCallback; }
1192             set
1193             {
1194                 if (ReadOnly)
1195                 {
1196                     throw new InvalidOperationException(SR.Get(SRID.ReadOnlyDesignerCoersionNotAllowed, Name));
1197                 }
1198  
1199                 _designerCoerceValueCallback = value;
1200             }
1201         }
1202  
1203         /// <summary> Standard unset value </summary>
1204         public static readonly object UnsetValue = new NamedObject("DependencyProperty.UnsetValue");
1205  
1206         private string _name;
1207         private Type _propertyType;
1208         private Type _ownerType;
1209         private PropertyMetadata _defaultMetadata;
1210         private ValidateValueCallback _validateValueCallback;
1211         private DependencyPropertyKey _readOnlyKey;
1212  
1213  
1214         [Flags]
1215         private enum Flags : int
1216         {
1217             GlobalIndexMask                           = 0x0000FFFF,
1218             IsValueType                               = 0x00010000,
1219             IsFreezableType                           = 0x00020000,
1220             IsStringType                              = 0x00040000,
1221             IsPotentiallyInherited                    = 0x00080000,
1222             IsDefaultValueChanged                     = 0x00100000,
1223             IsPotentiallyUsingDefaultValueFactory     = 0x00200000,
1224             IsObjectType                              = 0x00400000,
1225             // 0xFF800000   free bits
1226         }
1227  
1228         private Flags _packedData;
1229  
1230         // Synchronized (write locks, lock-free reads): Covered by DependencyProperty instance
1231         // This is a map that contains the IDs of derived classes that have overriden metadata
1232         /* property */ internal InsertionSortMap _metadataMap = new InsertionSortMap();
1233  
1234         private CoerceValueCallback _designerCoerceValueCallback;
1235  
1236         // Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
1237         /* property */ internal static ItemStructList<DependencyProperty> RegisteredPropertyList = new ItemStructList<DependencyProperty>(768);
1238  
1239         // Synchronized: Covered by DependencyProperty.Synchronized
1240         private static Hashtable PropertyFromName = new Hashtable();
1241  
1242         // Synchronized: Covered by DependencyProperty.Synchronized
1243         private static int GlobalIndexCount;
1244  
1245         // Global, cross-object synchronization
1246         internal static object Synchronized = new object();
1247  
1248         // Nullable Type
1249         private static Type NullableType = typeof(Nullable<>);
1250  
1251         /// <summary>
1252         ///     Returns the number of all registered properties.
1253         /// </summary>
1254         internal static int RegisteredPropertyCount {
1255             get {
1256                 return RegisteredPropertyList.Count;
1257             }
1258         }
1259  
1260         /// <summary>
1261         ///     Returns an enumeration of properties that are
1262         ///     currently registered.
1263         ///     Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
1264         /// </summary>
1265         internal static IEnumerable RegisteredProperties {
1266             get {
1267                 foreach(DependencyProperty dp in RegisteredPropertyList.List) {
1268                     if (dp != null) {
1269                         yield return dp;
1270                     }
1271                 }
1272             }
1273         }
1274  
1275     }
1276 }

 

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