zoukankan      html  css  js  c++  java
  • WPF 依赖属性源码 洞察微软如何实现DependencyProperty

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

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

       1 File: BaseSystemWindowsDependencyProperty.cs
       2 Project: wpfsrcWindowsBase.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 }
  • 相关阅读:
    树、森林和二叉树的转换
    弱校ACM奋斗史
    安徽科技学院2016-2017-1学期2013信息与计算科学12班期末测试_题解
    安徽省2016“京胜杯”程序设计大赛_K_纸上谈兵
    安徽省2016“京胜杯”程序设计大赛_J_YZK的大别墅
    安徽省2016“京胜杯”程序设计大赛_I_恶魔A+B
    安徽省2016“京胜杯”程序设计大赛_H_单身晚会
    安徽省2016“京胜杯”程序设计大赛_G_木条染色
    安徽省2016“京胜杯”程序设计大赛_F_吃在工大
    LeetCode() Merge Intervals 还是有问题,留待,脑袋疼。
  • 原文地址:https://www.cnblogs.com/yuanchenhui/p/DependencyProperty.html
Copyright © 2011-2022 走看看