DependencyProperty.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Base / System / Windows / DependencyProperty.cs / 1305600 / DependencyProperty.cs

                            using System; 
using System.Collections;
using System.Collections.Generic;
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"); 
            }
        }

        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 (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 & run static constructors if needed. 
        /// 
        /// 
        ///     The supplied metadata will be merged with the type's base
        ///     metadata 
        /// 
        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");
            } 

            // 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);
            } 
        } 

        ///  
        ///     Returns the DependencyPropertyKey associated with this DP.
        /// 
        internal DependencyPropertyKey DependencyPropertyKey
        { 
            get
            { 
                return _readOnlyKey; 
            }
        } 

        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 
                        MS.Internal.WindowsBase.SecurityHelper.RunClassConstructor(ownerType); 

                        // 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++;
        } 

        /// 
        /// This is the callback designers use to participate in the computation of property
        /// values at design time. Eg. Even if the author sets Visibility to Hidden, the designer 
        /// wants to coerce the value to Visible at design time so that the element doesn't
        /// disappear from the design surface. 
        ///  
        internal CoerceValueCallback DesignerCoerceValueCallback
        { 
            get {  return _designerCoerceValueCallback; }
            set
            {
                if (ReadOnly) 
                {
                    throw new InvalidOperationException(SR.Get(SRID.ReadOnlyDesignerCoersionNotAllowed, Name)); 
                } 

                _designerCoerceValueCallback = value; 
            }
        }

        ///  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(); 
 
        private CoerceValueCallback _designerCoerceValueCallback;
 
        // 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