DependencyProperty.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Base / System / Windows / DependencyProperty.cs / 2 / DependencyProperty.cs

                            using System; 
using System.Collections;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading; 
using System.Globalization;
using System.ComponentModel; 
using System.Windows.Markup;// For ValueSerializerAttribute 
using System.Windows.Threading; // For DispatcherObject
using System.Security.Permissions; // For LinkDemand 
using MS.Utility;
using MS.Internal.WindowsBase;
using System.Reflection;   // for IsInstanceOfType
using MS.Internal; 

#pragma warning disable 1634, 1691  // suppressing PreSharp warnings 
 
namespace System.Windows
{ 
    /// 
    ///     An attached dependency-based property
    /// 
    [TypeConverter("System.Windows.Markup.DependencyPropertyConverter, PresentationFramework, Version=" + Microsoft.Internal.BuildInfo.WCP_VERSION + ", Culture=neutral, PublicKeyToken=" + Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_TOKEN + ", Custom=null")] 
    [ValueSerializer(typeof(DependencyPropertyValueSerializer))]
    public sealed class DependencyProperty 
    { 
        /// 
        ///     Register a Dependency Property 
        /// 
        /// Name of property
        /// Type of the property
        /// Type that is registering the property 
        /// Dependency Property
        public static DependencyProperty Register(string name, Type propertyType, Type ownerType) 
        { 
            // Forwarding
            return Register(name, propertyType, ownerType, null, null); 
        }

        /// 
        ///     Register a Dependency Property 
        /// 
        /// Name of property 
        /// Type of the property 
        /// Type that is registering the property
        /// Metadata to use if current type doesn't specify type-specific metadata 
        /// Dependency Property
        public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
        {
            // Forwarding 
            return Register(name, propertyType, ownerType, typeMetadata, null);
        } 
 
        /// 
        ///     Register a Dependency Property 
        /// 
        /// Name of property
        /// Type of the property
        /// Type that is registering the property 
        /// Metadata to use if current type doesn't specify type-specific metadata
        /// Provides additional value validation outside automatic type validation 
        /// Dependency Property 
        public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
        { 
            RegisterParameterValidation(name, propertyType, ownerType);

            // Register an attached property
            PropertyMetadata defaultMetadata = null; 
            if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
            { 
                defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue); 
            }
 
            DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);

            if (typeMetadata != null)
            { 
                // Apply type-specific metadata to owner type only
                property.OverrideMetadata(ownerType, typeMetadata); 
            } 

            return property; 
        }

        /// 
        ///  Simple registration, metadata, validation, and a read-only property 
        /// key.  Calling this version restricts the property such that it can
        /// only be set via the corresponding overload of DependencyObject.SetValue. 
        ///  
        public static DependencyPropertyKey RegisterReadOnly(
            string name, 
            Type propertyType,
            Type ownerType,
            PropertyMetadata typeMetadata )
        { 
            return RegisterReadOnly( name, propertyType, ownerType, typeMetadata, null );
        } 
 
        /// 
        ///  Simple registration, metadata, validation, and a read-only property 
        /// key.  Calling this version restricts the property such that it can
        /// only be set via the corresponding overload of DependencyObject.SetValue.
        /// 
        public static DependencyPropertyKey RegisterReadOnly( 
            string name,
            Type propertyType, 
            Type ownerType, 
            PropertyMetadata typeMetadata,
            ValidateValueCallback validateValueCallback ) 
        {
            RegisterParameterValidation(name, propertyType, ownerType);

            PropertyMetadata defaultMetadata = null; 

            if (typeMetadata != null && typeMetadata.DefaultValueWasSet()) 
            { 
                defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
            } 
            else
            {
                defaultMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType);
            } 

            //  We create a DependencyPropertyKey at this point with a null property 
            // and set that in the _readOnlyKey field.  This is so the property is 
            // marked as requiring a key immediately.  If something fails in the
            // initialization path, the property is still marked as needing a key. 
            //  This is better than the alternative of creating and setting the key
            // later, because if that code fails the read-only property would not
            // be marked read-only.  The intent of this mildly convoluted code
            // is so we fail securely. 
            DependencyPropertyKey authorizationKey = new DependencyPropertyKey(null); // No property yet, use null as placeholder.
 
            DependencyProperty property = RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback); 

            property._readOnlyKey = authorizationKey; 

            authorizationKey.SetDependencyProperty(property);

            if (typeMetadata == null ) 
            {
                // No metadata specified, generate one so we can specify the authorized key. 
                typeMetadata = AutoGeneratePropertyMetadata(propertyType,validateValueCallback,name,ownerType); 
            }
 
            // Authorize registering type for read-only access, create key.
            #pragma warning suppress 6506 // typeMetadata is never null, since we generate default metadata if none is provided.

            // Apply type-specific metadata to owner type only 
            property.OverrideMetadata(ownerType, typeMetadata, authorizationKey);
 
            return authorizationKey; 
        }
 
        /// 
        ///  Simple registration, metadata, validation, and a read-only property
        /// key.  Calling this version restricts the property such that it can
        /// only be set via the corresponding overload of DependencyObject.SetValue. 
        /// 
        public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata) 
        { 
            return RegisterAttachedReadOnly( name, propertyType, ownerType, defaultMetadata, null );
        } 

        /// 
        ///  Simple registration, metadata, validation, and a read-only property
        /// key.  Calling this version restricts the property such that it can 
        /// only be set via the corresponding overload of DependencyObject.SetValue.
        ///  
        public static DependencyPropertyKey RegisterAttachedReadOnly(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback) 
        {
            RegisterParameterValidation(name, propertyType, ownerType); 

            // Establish default metadata for all types, if none is provided
            if (defaultMetadata == null)
            { 
                defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
            } 
 
            //  We create a DependencyPropertyKey at this point with a null property
            // and set that in the _readOnlyKey field.  This is so the property is 
            // marked as requiring a key immediately.  If something fails in the
            // initialization path, the property is still marked as needing a key.
            //  This is better than the alternative of creating and setting the key
            // later, because if that code fails the read-only property would not 
            // be marked read-only.  The intent of this mildly convoluted code
            // is so we fail securely. 
            DependencyPropertyKey authorizedKey = new DependencyPropertyKey(null); 

            DependencyProperty property = RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback); 

            property._readOnlyKey = authorizedKey;

            authorizedKey.SetDependencyProperty(property); 

            return authorizedKey; 
        } 

        ///  
        ///     Register an attached Dependency Property
        /// 
        /// Name of property
        /// Type of the property 
        /// Type that is registering the property
        /// Dependency Property 
        public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType) 
        {
            // Forwarding 
            return RegisterAttached(name, propertyType, ownerType, null, null );
        }

        ///  
        ///     Register an attached Dependency Property
        ///  
        /// Name of property 
        /// Type of the property
        /// Type that is registering the property 
        /// Metadata to use if current type doesn't specify type-specific metadata
        /// Dependency Property
        public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata)
        { 
            // Forwarding
            return RegisterAttached(name, propertyType, ownerType, defaultMetadata, null ); 
        } 

        ///  
        ///     Register an attached Dependency Property
        /// 
        /// Name of property
        /// Type of the property 
        /// Type that is registering the property
        /// Metadata to use if current type doesn't specify type-specific metadata 
        /// Provides additional value validation outside automatic type validation 
        /// Dependency Property
        public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback) 
        {
            RegisterParameterValidation(name, propertyType, ownerType);

            return RegisterCommon( name, propertyType, ownerType, defaultMetadata, validateValueCallback ); 
        }
 
        private static void RegisterParameterValidation(string name, Type propertyType, Type ownerType) 
        {
            if (name == null) 
            {
                throw new ArgumentNullException("name");
            }
 
            if (name.Length == 0)
            { 
                throw new ArgumentException(SR.Get(SRID.StringEmpty), "name"); 
            }
 
            if (ownerType == null)
            {
                throw new ArgumentNullException("ownerType");
            } 

            if (propertyType == null) 
            { 
                throw new ArgumentNullException("propertyType");
            } 

#if DEBUG  // IsCallerType is returning bool, and cannot be set with Conditional debug otherwise.
            Debug.Assert(IsCallerOfType(ownerType), String.Format(CultureInfo.CurrentUICulture, "Provided OwnerType does not match property registration caller (OwnerType='{0}', Property='{1}')", ownerType.Name, name));
#endif 
        }
 
        private static DependencyProperty RegisterCommon(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback) 
        {
            FromNameKey key = new FromNameKey(name, ownerType); 
            lock (Synchronized)
            {
                if (PropertyFromName.Contains(key))
                { 
                    throw new ArgumentException(SR.Get(SRID.PropertyAlreadyRegistered, name, ownerType.Name));
                } 
            } 

            // Establish default metadata for all types, if none is provided 
            if (defaultMetadata == null)
            {
                defaultMetadata = AutoGeneratePropertyMetadata( propertyType, validateValueCallback, name, ownerType );
            } 
            else // Metadata object is provided.
            { 
                // If the defaultValue wasn't specified auto generate one 
                if (!defaultMetadata.DefaultValueWasSet())
                { 
                    defaultMetadata.DefaultValue = AutoGenerateDefaultValue(propertyType);
                }

                ValidateMetadataDefaultValue( defaultMetadata, propertyType, name, validateValueCallback ); 
            }
 
            // Create property 
            DependencyProperty dp = new DependencyProperty(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
 
            // Seal (null means being used for default metadata, calls OnApply)
            defaultMetadata.Seal(dp, null);

            if (defaultMetadata.IsInherited) 
            {
                dp._packedData |= Flags.IsPotentiallyInherited; 
            } 

            if (defaultMetadata.UsingDefaultValueFactory) 
            {
                dp._packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
            }
 

            // Map owner type to this property 
            // Build key 
            lock (Synchronized)
            { 
                PropertyFromName[key] = dp;
            }

 
            if( TraceDependencyProperty.IsEnabled )
            { 
                TraceDependencyProperty.TraceActivityItem( 
                    TraceDependencyProperty.Register,
                    dp, 
                    dp.OwnerType );
            }

 
            return dp;
        } 
 
        private static object AutoGenerateDefaultValue(
            Type propertyType) 
        {
            // Default per-type metadata not provided, create
            object defaultValue = null;
 
            // Auto-assigned default value
            if (propertyType.IsValueType) 
            { 
                // Value-types have default-constructed type default values
                defaultValue = Activator.CreateInstance(propertyType); 
            }

            return defaultValue;
        } 

        private static PropertyMetadata AutoGeneratePropertyMetadata( 
            Type propertyType, 
            ValidateValueCallback validateValueCallback,
            string name, 
            Type ownerType)
        {
            // Default per-type metadata not provided, create
            object defaultValue = AutoGenerateDefaultValue(propertyType); 

            // If a validator is passed in, see if the default value makes sense. 
            if ( validateValueCallback != null && 
                !validateValueCallback(defaultValue))
            { 
                // Didn't work - require the caller to specify one.
                throw new ArgumentException(SR.Get(SRID.DefaultValueAutoAssignFailed, name, ownerType.Name));
            }
 
            return new PropertyMetadata(defaultValue);
        } 
 
        // Validate the default value in the given metadata
        private static void ValidateMetadataDefaultValue( 
            PropertyMetadata defaultMetadata,
            Type propertyType,
            string propertyName,
            ValidateValueCallback validateValueCallback ) 
        {
            // If we are registered to use the DefaultValue factory we can 
            // not validate the DefaultValue at registration time, so we 
            // early exit.
            if (defaultMetadata.UsingDefaultValueFactory) 
            {
                return;
            }
 
            ValidateDefaultValueCommon(defaultMetadata.DefaultValue, propertyType,
                propertyName, validateValueCallback, /*checkThreadAffinity = */ true); 
        } 

        // Validate the given default value, used by PropertyMetadata.GetDefaultValue() 
        // when the DefaultValue factory is used.
        // These default values are allowed to have thread-affinity.
        internal void ValidateFactoryDefaultValue(object defaultValue)
        { 
            ValidateDefaultValueCommon(defaultValue, PropertyType, Name, ValidateValueCallback, false);
        } 
 
        private static void ValidateDefaultValueCommon(
            object defaultValue, 
            Type propertyType,
            string propertyName,
            ValidateValueCallback validateValueCallback,
            bool checkThreadAffinity) 
        {
            // Ensure default value is the correct type 
            if (!IsValidType(defaultValue, propertyType)) 
            {
                throw new ArgumentException(SR.Get(SRID.DefaultValuePropertyTypeMismatch, propertyName)); 
            }

            // An Expression used as default value won't behave as expected since
            //  it doesn't get evaluated.  We explicitly fail it here. 
            if (defaultValue is Expression )
            { 
                throw new ArgumentException(SR.Get(SRID.DefaultValueMayNotBeExpression)); 
            }
 
            if (checkThreadAffinity)
            {
                // If the default value is a DispatcherObject with thread affinity
                // we cannot accept it as a default value. If it implements ISealable 
                // we attempt to seal it; if not we throw  an exception. Types not
                // deriving from DispatcherObject are allowed - it is up to the user to 
                // make any custom types free-threaded. 

                DispatcherObject dispatcherObject = defaultValue as DispatcherObject; 

                if (dispatcherObject != null && dispatcherObject.Dispatcher != null)
                {
                    // Try to make the DispatcherObject free-threaded if it's an 
                    // ISealable.
 
                    ISealable valueAsISealable = dispatcherObject as ISealable; 

                    if (valueAsISealable != null && valueAsISealable.CanSeal) 
                    {
                        Invariant.Assert (!valueAsISealable.IsSealed,
                               "A Sealed ISealable must not have dispatcher affinity");
 
                        valueAsISealable.Seal();
 
                        Invariant.Assert(dispatcherObject.Dispatcher == null, 
                            "ISealable.Seal() failed after ISealable.CanSeal returned true");
                    } 
                    else
                    {
                        throw new ArgumentException(SR.Get(SRID.DefaultValueMustBeFreeThreaded, propertyName));
                    } 
                }
            } 
 

            // After checking for correct type, check default value against 
            //  validator (when one is given)
            if ( validateValueCallback != null &&
                !validateValueCallback(defaultValue))
            { 
                throw new ArgumentException(SR.Get(SRID.DefaultValueInvalid, propertyName));
            } 
        } 

 
        /// 
        ///     Parameter validation for OverrideMetadata, includes code to force
        /// all base classes of "forType" to register their metadata so we know
        /// what we are overriding. 
        /// 
        private void SetupOverrideMetadata( 
                Type forType, 
                PropertyMetadata typeMetadata,
            out DependencyObjectType dType, 
            out PropertyMetadata baseMetadata )
        {
            if (forType == null)
            { 
                throw new ArgumentNullException("forType");
            } 
#if DEBUG  // IsCallerType is returning bool, and cannot be set with Conditional debug otherwise. 
            Debug.Assert(IsCallerOfType(forType), String.Format(CultureInfo.CurrentUICulture, "Overriding metadata on other types is illegal (ForType='{0}', Property='{1}')", forType.Name, Name));
#endif 
            if (typeMetadata == null)
            {
                throw new ArgumentNullException("typeMetadata");
            } 

            if (typeMetadata.Sealed) 
            { 
                throw new ArgumentException(SR.Get(SRID.TypeMetadataAlreadyInUse));
            } 

            if (!typeof(DependencyObject).IsAssignableFrom(forType))
            {
                throw new ArgumentException(SR.Get(SRID.TypeMustBeDependencyObjectDerived, forType.Name)); 
            }
 
            // Ensure default value is a correct value (if it was supplied, 
            // otherwise, the default value will be taken from the base metadata
            // which was already validated) 
            if (typeMetadata.IsDefaultValueModified)
            {
                // Will throw ArgumentException if fails.
                ValidateMetadataDefaultValue( typeMetadata, PropertyType, Name, ValidateValueCallback ); 
            }
 
            // Force all base classes to register their metadata 
            dType = DependencyObjectType.FromSystemType(forType);
 
            // Get metadata for the base type
            baseMetadata = GetMetadata(dType.BaseType);

            // Make sure overriding metadata is the same type or derived type of 
            // the base metadata
            if (!baseMetadata.GetType().IsAssignableFrom(typeMetadata.GetType())) 
            { 
                throw new ArgumentException(SR.Get(SRID.OverridingMetadataDoesNotMatchBaseMetadataType));
            } 
        }

        /// 
        ///     Supply metadata for given type 
        /// 
        ///  
        ///     The supplied metadata will be merged with the type's base 
        ///     metadata
        ///  
        /// Type to associate metadata
        /// The metadata to use
        public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata)
        { 
            DependencyObjectType dType;
            PropertyMetadata baseMetadata; 
 
            SetupOverrideMetadata( forType, typeMetadata, out dType, out baseMetadata );
 
            if( ReadOnly )
            {
                // Readonly and no DependencyPropertyKey - not allowed.
                throw new InvalidOperationException(SR.Get(SRID.ReadOnlyOverrideNotAllowed, Name)); 
            }
 
            ProcessOverrideMetadata( forType, typeMetadata, dType, baseMetadata ); 
        }
 
        /// 
        ///     Supply metadata for a given type, overriding a property that is
        /// read-only.  If property is not read only, tells user to use the Plain
        /// Jane OverrideMetadata instead. 
        /// 
        public void OverrideMetadata(Type forType, PropertyMetadata typeMetadata, DependencyPropertyKey key) 
        { 
            DependencyObjectType dType;
            PropertyMetadata baseMetadata; 

            SetupOverrideMetadata( forType, typeMetadata, out dType, out baseMetadata );

            if( key == null ) 
            {
                throw new ArgumentNullException("key"); 
            } 

            if( ReadOnly ) 
            {
                // If the property is read-only, the key must match this property
                //  and the key must match that in the base metadata.
 
                if( key.DependencyProperty != this )
                { 
                    throw new ArgumentException(SR.Get(SRID.ReadOnlyOverrideKeyNotAuthorized, Name)); 
                }
 
                VerifyReadOnlyKey(key);
            }
            else
            { 
                throw new InvalidOperationException(SR.Get(SRID.PropertyNotReadOnly));
            } 
 
            // Either the property doesn't require a key, or the key match was
            //  successful.  Proceed with the metadata override. 
            ProcessOverrideMetadata( forType, typeMetadata, dType, baseMetadata );
        }

        ///  
        ///     After parameters have been validated for OverrideMetadata, this
        /// method is called to actually update the data structures. 
        ///  
        private void ProcessOverrideMetadata(
            Type forType, 
            PropertyMetadata typeMetadata,
            DependencyObjectType dType,
            PropertyMetadata baseMetadata)
        { 
            // Store per-Type metadata for this property. Locks only on Write.
            // Datastructure guaranteed to be valid for non-locking readers 
            lock (Synchronized) 
            {
                if (DependencyProperty.UnsetValue == _metadataMap[dType.Id]) 
                {
                    _metadataMap[dType.Id] = typeMetadata;
                }
                else 
                {
                    throw new ArgumentException(SR.Get(SRID.TypeMetadataAlreadyRegistered, forType.Name)); 
                } 
           }
 
            // Merge base's metadata into this metadata
            // CALLBACK
            typeMetadata.InvokeMerge(baseMetadata, this);
 
            // Type metadata may no longer change (calls OnApply)
            typeMetadata.Seal(this, forType); 
 
            if (typeMetadata.IsInherited)
            { 
                _packedData |= Flags.IsPotentiallyInherited;
            }

            if (typeMetadata.DefaultValueWasSet() && (typeMetadata.DefaultValue != DefaultMetadata.DefaultValue)) 
            {
                _packedData |= Flags.IsDefaultValueChanged; 
            } 

            if (typeMetadata.UsingDefaultValueFactory) 
            {
                _packedData |= Flags.IsPotentiallyUsingDefaultValueFactory;
            }
        } 

 
        [FriendAccessAllowed]   // Built into Base, also used by Core & Framework. 
        internal object GetDefaultValue(DependencyObjectType dependencyObjectType)
        { 
            if (!IsDefaultValueChanged)
            {
                return DefaultMetadata.DefaultValue;
            } 

            return GetMetadata(dependencyObjectType).DefaultValue; 
        } 

        [FriendAccessAllowed]   // Built into Base, also used by Core & Framework. 
        internal object GetDefaultValue(Type forType)
        {
            if (!IsDefaultValueChanged)
            { 
                return DefaultMetadata.DefaultValue;
            } 
 
            return GetMetadata(DependencyObjectType.FromSystemTypeInternal(forType)).DefaultValue;
        } 

        /// 
        ///     Retrieve metadata for a provided type
        ///  
        /// Type to get metadata
        /// Property metadata 
        public PropertyMetadata GetMetadata(Type forType) 
        {
            if (forType != null) 
            {
                return GetMetadata(DependencyObjectType.FromSystemType(forType));
            }
            throw new ArgumentNullException("forType"); 
        }
 
        ///  
        ///     Retrieve metadata for a provided DependencyObject
        ///  
        /// DependencyObject to get metadata
        /// Property metadata
        public PropertyMetadata GetMetadata(DependencyObject dependencyObject)
        { 
            if (dependencyObject != null)
            { 
                return GetMetadata(dependencyObject.DependencyObjectType); 
            }
            throw new ArgumentNullException("dependencyObject"); 
        }

        /// 
        /// Reteive metadata for a DependencyObject type described by the 
        /// given DependencyObjectType
        ///  
        //CASRemoval:[StrongNameIdentityPermission(SecurityAction.LinkDemand, PublicKey = Microsoft.Internal.BuildInfo.WCP_PUBLIC_KEY_STRING)] 
        public PropertyMetadata GetMetadata(DependencyObjectType dependencyObjectType)
        { 
            // All static constructors for this DType and all base types have already
            // been run. If no overriden metadata was provided, then look up base types.
            // If no metadata found on base types, then return default
 
            if (null != dependencyObjectType)
            { 
                // Do we in fact have any overrides at all? 
                int index = _metadataMap.Count - 1;
                int Id; 
                object value;

                if (index < 0)
                { 
                    // No overrides or it's the base class
                    return _defaultMetadata; 
                } 
                else if (index == 0)
                { 
                    // Only 1 override
                    _metadataMap.GetKeyValuePair(index, out Id, out value);

                    // If there is overriden metadata, then there is a base class with 
                    // lower or equal Id of this class, or this class is already a base class
                    // of the overridden one. Therefore dependencyObjectType won't ever 
                    // become null before we exit the while loop 
                    while (dependencyObjectType.Id > Id)
                    { 
                        dependencyObjectType = dependencyObjectType.BaseType;
                    }

                    if (Id == dependencyObjectType.Id) 
                    {
                        // Return the override 
                        return (PropertyMetadata)value; 
                    }
                    // Return default metadata 
                }
                else
                {
                    // We have more than 1 override for this class, so we will have to loop through 
                    // both the overrides and the class Id
                    if (0 != dependencyObjectType.Id) 
                    { 
                        do
                        { 
                            // Get the Id of the most derived class with overridden metadata
                            _metadataMap.GetKeyValuePair(index, out Id, out value);
                            --index;
 
    						// If the Id of this class is less than the override, then look for an override
    						// with an equal or lower Id until we run out of overrides 
    						while ((dependencyObjectType.Id < Id) && (index >= 0)) 
                            {
                                _metadataMap.GetKeyValuePair(index, out Id, out value); 
                                --index;
                            }

                            // If there is overriden metadata, then there is a base class with 
                            // lower or equal Id of this class, or this class is already a base class
                            // of the overridden one. Therefore dependencyObjectType won't ever 
                            // become null before we exit the while loop 
    						while (dependencyObjectType.Id > Id)
                            { 
                                dependencyObjectType = dependencyObjectType.BaseType;
                            }

                            if (Id == dependencyObjectType.Id) 
                            {
                                // Return the override 
                                return (PropertyMetadata)value; 
                            }
                        } 
                        while (index >= 0);
                    }
                }
            } 
            return _defaultMetadata;
        } 
 

        ///  
        ///     Associate another owner type with this property
        /// 
        /// 
        ///     The owner type is used when resolving a property by name () 
        /// 
        /// Additional owner type 
        /// This property 
        public DependencyProperty AddOwner(Type ownerType)
        { 
            // Forwarding
            return AddOwner(ownerType, null);
        }
 
        /// 
        ///     Associate another owner type with this property 
        ///  
        /// 
        ///     The owner type is used when resolving a property by name () 
        /// 
        /// Additional owner type
        /// Optional type metadata to override on owner's behalf
        /// This property 
        public DependencyProperty AddOwner(Type ownerType, PropertyMetadata typeMetadata)
        { 
            if (ownerType == null) 
            {
                throw new ArgumentNullException("ownerType"); 
            }

#if DEBUG  // IsCallerType is returning bool, and cannot be set with Conditional debug otherwise.
            Debug.Assert(IsCallerOfType(ownerType), String.Format(CultureInfo.CurrentUICulture, "Provided OwnerType does not match caller (OwnerType='{0}')", ownerType.Name)); 
#endif
            // Map owner type to this property 
            // Build key 
            FromNameKey key = new FromNameKey(Name, ownerType);
 
            lock (Synchronized)
            {
                if (PropertyFromName.Contains(key))
                { 
                    throw new ArgumentException(SR.Get(SRID.PropertyAlreadyRegistered, Name, ownerType.Name));
                } 
            } 

            if (typeMetadata != null) 
            {
                OverrideMetadata(ownerType, typeMetadata);
            }
 

            lock (Synchronized) 
            { 
                PropertyFromName[key] = this;
            } 


            return this;
        } 

 
        ///  
        ///     Name of the property
        ///  
        public string Name
        {
            get { return _name; }
        } 

        ///  
        ///     Type of the property 
        /// 
        public Type PropertyType 
        {
            get { return _propertyType; }
        }
 
        /// 
        ///     Owning type of the property 
        ///  
        public Type OwnerType
        { 
            get { return _ownerType; }
        }

        ///  
        ///     Default metadata for the property
        ///  
        public PropertyMetadata DefaultMetadata 
        {
            get { return _defaultMetadata; } 
        }

        /// 
        ///     Value validation callback 
        /// 
        public ValidateValueCallback ValidateValueCallback 
        { 
            get { return _validateValueCallback; }
        } 

        /// 
        ///     Zero-based globally unique index of the property
        ///  
        public int GlobalIndex
        { 
            get { return (int) (_packedData & Flags.GlobalIndexMask); } 
        }
 
        internal bool IsObjectType
        {
            get { return (_packedData & Flags.IsObjectType) != 0; }
        } 

        internal bool IsValueType 
        { 
            get { return (_packedData & Flags.IsValueType) != 0; }
        } 

        internal bool IsFreezableType
        {
            get { return (_packedData & Flags.IsFreezableType) != 0; } 
        }
 
        internal bool IsStringType 
        {
            get { return (_packedData & Flags.IsStringType) != 0; } 
        }

        internal bool IsPotentiallyInherited
        { 
            get { return (_packedData & Flags.IsPotentiallyInherited) != 0; }
        } 
 
        internal bool IsDefaultValueChanged
        { 
            get { return (_packedData & Flags.IsDefaultValueChanged) != 0; }
        }

        internal bool IsPotentiallyUsingDefaultValueFactory 
        {
            get { return (_packedData & Flags.IsPotentiallyUsingDefaultValueFactory) != 0; } 
        } 

        ///  
        ///     Serves as a hash function for a particular type, suitable for use in
        ///     hashing algorithms and data structures like a hash table
        /// 
        /// The DependencyProperty's GlobalIndex 
        public override int GetHashCode()
        { 
            return GlobalIndex; 
        }
 
        /// 
        ///     Used to determine if given value is appropriate for the type of the property
        /// 
        /// Value to check 
        /// true if value matches property type
        public bool IsValidType(object value) 
        { 
            return IsValidType(value, PropertyType);
        } 


        /// 
        ///     Used to determine if given value is appropriate for the type of the property 
        ///     and the range of values (as specified via the ValidateValueCallback) within that type
        ///  
        /// Value to check 
        /// true if value is appropriate
        public bool IsValidValue(object value) 
        {
            if (!IsValidType(value, PropertyType))
            {
                return false; 
            }
 
            if (ValidateValueCallback != null) 
            {
                // CALLBACK 
                return ValidateValueCallback(value);
            }

            return true; 
        }
 
        ///  
        ///     Set/Value value disabling
        ///  
        public bool ReadOnly
        {
            get
            { 
                return (_readOnlyKey != null);
            } 
        } 

        internal void VerifyReadOnlyKey( DependencyPropertyKey candidateKey ) 
        {
            Debug.Assert( ReadOnly, "Why are we trying to validate read-only key on a property that is not read-only?");

            if (_readOnlyKey != candidateKey) 
            {
                throw new ArgumentException(SR.Get(SRID.ReadOnlyKeyNotAuthorized)); 
            } 
        }
 
        /// 
        ///     Internal version of IsValidValue that bypasses IsValidType check;
        ///     Called from SetValueInternal
        ///  
        /// Value to check
        /// true if value is appropriate 
        internal bool IsValidValueInternal(object value) 
        {
            if (ValidateValueCallback != null) 
            {
                // CALLBACK
                return ValidateValueCallback(value);
            } 

            return true; 
        } 

        ///  
        ///     Find a property from name
        /// 
        /// 
        ///     Search includes base classes of the provided type as well 
        /// 
        /// Name of the property 
        /// Owner type of the property 
        /// Dependency property
        [FriendAccessAllowed]   // Built into Base, also used by Framework. 
        internal static DependencyProperty FromName(string name, Type ownerType)
        {
            DependencyProperty dp = null;
 
            if (name != null)
            { 
                if (ownerType != null) 
                {
                    FromNameKey key = new FromNameKey(name, ownerType); 

                    while ((dp == null) && (ownerType != null))
                    {
                        // Ensure static constructor of type has run 
                        RuntimeHelpers.RunClassConstructor(ownerType.TypeHandle);
 
                        // Locate property 
                        key.UpdateNameKey(ownerType);
 
                        lock (Synchronized)
                        {
                            dp = (DependencyProperty)PropertyFromName[key];
                        } 

                        ownerType = ownerType.BaseType; 
                    } 
                }
                else 
                {
                    throw new ArgumentNullException("ownerType");
                }
            } 
            else
            { 
                throw new ArgumentNullException("name"); 
            }
            return dp; 
        }


        ///  
        ///    String representation
        ///  
        public override string ToString() 
        {
            return _name; 
        }


        internal static bool IsValidType(object value, Type propertyType) 
        {
            if (value == null) 
            { 
                // Null values are invalid for value-types
                if (propertyType.IsValueType && 
                    !(propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == NullableType))
                {
                    return false;
                } 
            }
            else 
            { 
                // Non-null default value, ensure its the correct type
                if (!propertyType.IsInstanceOfType(value)) 
                {
                    return false;
                }
            } 

            return true; 
        } 

        private class FromNameKey 
        {
            public FromNameKey(string name, Type ownerType)
            {
                _name = name; 
                _ownerType = ownerType;
 
                _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode(); 
            }
 
            public void UpdateNameKey(Type ownerType)
            {
                _ownerType = ownerType;
 
                _hashCode = _name.GetHashCode() ^ _ownerType.GetHashCode();
            } 
 
            public override int GetHashCode()
            { 
                return _hashCode;
            }

            public override bool Equals(object o) 
            {
                if ((o != null) && (o is FromNameKey)) 
                { 
                    return Equals((FromNameKey)o);
                } 
                else
                {
                    return false;
                } 
            }
 
            public bool Equals(FromNameKey key) 
            {
                return (_name.Equals(key._name) && (_ownerType == key._ownerType)); 
            }

            private string _name;
            private Type _ownerType; 

            private int _hashCode; 
        } 

 
        private DependencyProperty(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
        {
            _name = name;
            _propertyType = propertyType; 
            _ownerType = ownerType;
            _defaultMetadata = defaultMetadata; 
            _validateValueCallback = validateValueCallback; 

            Flags packedData; 
            lock (Synchronized)
            {
                packedData = (Flags) GetUniqueGlobalIndex(ownerType, name);
 
                RegisteredPropertyList.Add(this);
            } 
 
            if (propertyType.IsValueType)
            { 
                packedData |= Flags.IsValueType;
            }

            if (propertyType == typeof(object)) 
            {
                packedData |= Flags.IsObjectType; 
            } 

            if (typeof(Freezable).IsAssignableFrom(propertyType)) 
            {
                packedData |= Flags.IsFreezableType;
            }
 
            if (propertyType == typeof(string))
            { 
                packedData |= Flags.IsStringType; 
            }
 
            _packedData = packedData;
        }

        // Synchronized: Covered by DependencyProperty.Synchronized 
        internal static int GetUniqueGlobalIndex(Type ownerType, string name)
        { 
            // Prevent GlobalIndex from overflow. DependencyProperties are meant to be static members and are to be registered 
            // only via static constructors. However there is no cheap way of ensuring this, without having to do a stack walk. Hence
            // concievably people could register DependencyProperties via instance methods and therefore cause the GlobalIndex to 
            // overflow. This check will explicitly catch this error, instead of silently malfuntioning.
            if (GlobalIndexCount >= (int)Flags.GlobalIndexMask)
            {
                if (ownerType != null) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.TooManyDependencyProperties, ownerType.Name + "." + name)); 
                } 
                else
                { 
                    throw new InvalidOperationException(SR.Get(SRID.TooManyDependencyProperties, "ConstantProperty"));
                }
            }
 
            // Covered by Synchronized by caller
            return GlobalIndexCount++; 
        } 

#if DEBUG 
        //
        // Determine if the current caller is of the specified type
        //
        private static bool IsCallerOfType(Type type) 
        {
            StackTrace stackTrace = new StackTrace(); 
 
            // Walk stack until caller type is found
            StackFrame stackFrame; 
            MethodBase methodBase;
            for (int i = 0; i < stackTrace.FrameCount; i++)
            {
                stackFrame = stackTrace.GetFrame(i); 
                methodBase = stackFrame.GetMethod();
 
                if (type == methodBase.DeclaringType) 
                {
                    return true; 
                }
            }

            // Caller's type was not found 
            return false;
        } 
#endif 

 
        ///  Standard unset value 
        public static readonly object UnsetValue = new NamedObject("DependencyProperty.UnsetValue");

        private string _name; 
        private Type _propertyType;
        private Type _ownerType; 
        private PropertyMetadata _defaultMetadata; 
        private ValidateValueCallback _validateValueCallback;
        private DependencyPropertyKey _readOnlyKey; 


        [Flags]
        private enum Flags : int 
        {
            GlobalIndexMask                           = 0x0000FFFF, 
            IsValueType                               = 0x00010000, 
            IsFreezableType                           = 0x00020000,
            IsStringType                              = 0x00040000, 
            IsPotentiallyInherited                    = 0x00080000,
            IsDefaultValueChanged                     = 0x00100000,
            IsPotentiallyUsingDefaultValueFactory     = 0x00200000,
            IsObjectType                              = 0x00400000, 
            // 0xFF800000   free bits
        } 
 
        private Flags _packedData;
 
        // Synchronized (write locks, lock-free reads): Covered by DependencyProperty instance
        // This is a map that contains the IDs of derived classes that have overriden metadata
        /* property */ internal InsertionSortMap _metadataMap = new InsertionSortMap();
 
        // Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
        /* property */ internal static ItemStructList RegisteredPropertyList = new ItemStructList(768); 
 
        // Synchronized: Covered by DependencyProperty.Synchronized
        private static Hashtable PropertyFromName = new Hashtable(); 

        // Synchronized: Covered by DependencyProperty.Synchronized
        private static int GlobalIndexCount;
 
        // Global, cross-object synchronization
        internal static object Synchronized = new object(); 
 
        // Nullable Type
        private static Type NullableType = typeof(Nullable<>); 

        /// 
        ///     Returns the number of all registered properties.
        ///  
        internal static int RegisteredPropertyCount {
            get { 
                return RegisteredPropertyList.Count; 
            }
        } 

        /// 
        ///     Returns an enumeration of properties that are
        ///     currently registered. 
        ///     Synchronized (write locks, lock-free reads): Covered by DependencyProperty.Synchronized
        ///  
        internal static IEnumerable RegisteredProperties { 
            get {
                foreach(DependencyProperty dp in RegisteredPropertyList.List) { 
                    if (dp != null) {
                        yield return dp;
                    }
                } 
            }
        } 
    } 
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK