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 }
专注C#、C++。擅长WPF、WinForm、QT等技术。
研究ofd多年,开发了一些列产品。
技术交流QQ群:565438497。