DependencyPropertyDescriptor.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 / ComponentModel / DependencyPropertyDescriptor.cs / 1305600 / DependencyPropertyDescriptor.cs

                            using MS.Internal.ComponentModel; 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics; 
using System.Reflection;
using System.Text; 
using System.Security; 
using System.Windows;
 
#pragma warning disable 1634, 1691  // suppressing PreSharp warnings

namespace System.ComponentModel
{ 
    /// 
    ///     This is a wrapper property descriptor that offers a merged API of 
    ///     both CLR and DependencyProperty features.  To use it, call its 
    ///     static FromProperty method passing a PropertyDescriptor.  The
    ///     API degrades gracefully if the property descriptor passed does 
    ///     not represent a dependency property.
    /// 
    public sealed class DependencyPropertyDescriptor : PropertyDescriptor {
 
        //------------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        ///  
        ///     Creates a new dependency property descriptor.  A note on perf:  We don't
        ///     pass the property descriptor down as the default member descriptor here.  Doing 
        ///     so gets the attributes off of the property descriptor, which can be costly if they 
        ///     haven't been accessed yet.  Instead, we wait until someone needs to access our
        ///     Attributes property and demand create the attributes at that time. 
        /// 
        private DependencyPropertyDescriptor(PropertyDescriptor property, string name, Type componentType, DependencyProperty dp, bool isAttached) : base(name, null)
        {
            Debug.Assert(property != null || !isAttached, "Demand-load of property descriptor is only supported for direct properties"); 

            _property = property; 
            _componentType = componentType; 
            _dp = dp;
            _isAttached = isAttached; 
            _metadata = _dp.GetMetadata(componentType);
        }

        #endregion Constructors 

 
        //----------------------------------------------------- 
        //
        //  Public Methods 
        //
        //-----------------------------------------------------

        #region Public Methods 

        ///  
        ///     Static method that returns a DependencyPropertyDescriptor from a PropertyDescriptor. 
        /// 
        public static DependencyPropertyDescriptor FromProperty(PropertyDescriptor property) 
        {
            if (property == null) throw new ArgumentNullException("property");

            DependencyPropertyDescriptor dpd; 
            bool found;
 
            lock(_cache) 
            {
                found = _cache.TryGetValue(property, out dpd); 
            }

            if (found)
            { 
                return dpd;
            } 
 
            // Locate the dependency property.  We do this a fast way
            // by searching for InternalPropertyDescriptor, and a slow 
            // way, by looking for an attribute.  The fast way works unless
            // someone has added another layer of metadata overrides to
            // TypeDescriptor.
 
            DependencyProperty dp = null;
            bool isAttached = false; 
 
            DependencyObjectPropertyDescriptor idpd = property as DependencyObjectPropertyDescriptor;
            if (idpd != null) 
            {
                dp = idpd.DependencyProperty;
                isAttached = idpd.IsAttached;
            } 
            else
            { 
                #pragma warning suppress 6506 // property is obviously not null 
                DependencyPropertyAttribute dpa = property.Attributes[typeof(DependencyPropertyAttribute)] as DependencyPropertyAttribute;
                if (dpa != null) 
                {
                    dp = dpa.DependencyProperty;
                    isAttached = dpa.IsAttached;
                } 
            }
 
            if (dp != null) 
            {
                dpd = new DependencyPropertyDescriptor(property, property.Name, property.ComponentType, dp, isAttached); 

                lock(_cache)
                {
                    _cache[property] = dpd; 
                }
            } 
 
            return dpd;
        } 


        /// 
        ///     Static method that returns a DependencyPropertyDescriptor from a DependencyProperty.  The 
        ///     DependencyProperty may refer to either a direct or attached property.  The targetType is the
        ///     type of object to associate with the property:  either the owner type for a direct property 
        ///     or the type of object to attach to for an attached property. 
        /// 
        internal static DependencyPropertyDescriptor FromProperty(DependencyProperty dependencyProperty, Type ownerType, Type targetType, bool ignorePropertyType) 
        {
            if (dependencyProperty == null) throw new ArgumentNullException("dependencyProperty");
            if (targetType == null) throw new ArgumentNullException("targetType");
 
            // We have a different codepath here for attached and direct
            // properties.  For direct properties, we route through Type 
            // Descriptor because we need the underlying CLR property descriptor 
            // to create our wrapped property.  For attached properties, all we
            // need is the dp and the object type and we can create an attached 
            // property descriptor based on that.  We must special case attached
            // properties here because TypeDescriptor will only return attached
            // properties for instances, not types.
 
            DependencyPropertyDescriptor dpd = null;
 
            if (ownerType.GetProperty(dependencyProperty.Name) != null) 
            {
                // For direct properties we don't want to get the property descriptor 
                // yet because it is very expensive.  Delay it until needed.

                lock (_ignorePropertyTypeCache)
                { 
                    _ignorePropertyTypeCache.TryGetValue(dependencyProperty, out dpd);
                } 
 
                if (dpd == null)
                { 
                    // Create a new DPD based on the type information we have.  It
                    // will fill in the property descriptor by calling TypeDescriptor
                    // when needed.
 
                    dpd = new DependencyPropertyDescriptor(null, dependencyProperty.Name, targetType, dependencyProperty, false);
 
                    lock (_ignorePropertyTypeCache) 
                    {
                        _ignorePropertyTypeCache[dependencyProperty] = dpd; 
                    }
                }
            }
            else 
            {
                if (ownerType.GetMethod("Get" + dependencyProperty.Name) == null && 
                    ownerType.GetMethod("Set" + dependencyProperty.Name) == null) 
                {
                    return null; 
                }

                // If it isn't a direct property, we treat it as attached unless it is internal.
                // We should never release internal properties to the user 

                PropertyDescriptor prop = DependencyObjectProvider.GetAttachedPropertyDescriptor(dependencyProperty, targetType); 
                if (prop != null) 
                {
                    dpd = FromProperty(prop); 
                }
            }

            return dpd; 
        }
 
        ///  
        ///     Static method that returns a DependencyPropertyDescriptor from a DependencyProperty.  The
        ///     DependencyProperty may refer to either a direct or attached property.  The targetType is the 
        ///     type of object to associate with the property:  either the owner type for a direct property
        ///     or the type of object to attach to for an attached property.
        /// 
        public static DependencyPropertyDescriptor FromProperty(DependencyProperty dependencyProperty, Type targetType) 
        {
            if (dependencyProperty == null) throw new ArgumentNullException("dependencyProperty"); 
            if (targetType == null) throw new ArgumentNullException("targetType"); 

            // We have a different codepath here for attached and direct 
            // properties.  For direct properties, we route through Type
            // Descriptor because we need the underlying CLR property descriptor
            // to create our wrapped property.  For attached properties, all we
            // need is the dp and the object type and we can create an attached 
            // property descriptor based on that.  We must special case attached
            // properties here because TypeDescriptor will only return attached 
            // properties for instances, not types. 

            DependencyPropertyDescriptor dpd = null; 
            DependencyPropertyKind dpKind = DependencyObjectProvider.GetDependencyPropertyKind(dependencyProperty, targetType);

            if (dpKind.IsDirect)
            { 
                // For direct properties we don't want to get the property descriptor
                // yet because it is very expensive.  Delay it until needed. 
 
                lock(_cache)
                { 
                    _cache.TryGetValue(dependencyProperty, out dpd);
                }

                if (dpd == null) 
                {
                    // Create a new DPD based on the type information we have.  It 
                    // will fill in the property descriptor by calling TypeDescriptor 
                    // when needed.
 
                    dpd = new DependencyPropertyDescriptor(null, dependencyProperty.Name, targetType, dependencyProperty, false);

                    lock(_cache)
                    { 
                        _cache[dependencyProperty] = dpd;
                    } 
                } 
            }
            else if (!dpKind.IsInternal) 
            {
                // If it isn't a direct property, we treat it as attached unless it is internal.
                // We should never release internal properties to the user
 
                PropertyDescriptor prop = DependencyObjectProvider.GetAttachedPropertyDescriptor(dependencyProperty, targetType);
                if (prop != null) 
                { 
                    dpd = FromProperty(prop);
                } 
            }

            return dpd;
        } 

        ///  
        ///     Static method that returns a DependencyPropertyDescriptor for a given property name. 
        ///     The name may refer to a direct or attached property.  OwnerType is the type of
        ///     object that owns the property definition.  TargetType is the type of object you wish 
        ///     to set the property for.  For direct properties, they are the same type.  For attached
        ///     properties they usually differ.
        /// 
        public static DependencyPropertyDescriptor FromName(string name, Type ownerType, Type targetType) 
        {
            if (name == null) throw new ArgumentNullException("name"); 
            if (ownerType == null) throw new ArgumentNullException("ownerType"); 
            if (targetType == null) throw new ArgumentNullException("targetType");
 
            DependencyProperty dp = DependencyProperty.FromName(name, ownerType);
            if (dp != null)
            {
                return FromProperty(dp, targetType); 
            }
 
            return null; 
        }
 
        /// 
        ///     Static method that returns a DependencyPropertyDescriptor for a given property name.
        ///     The name may refer to a direct or attached property.  OwnerType is the type of
        ///     object that owns the property definition.  TargetType is the type of object you wish 
        ///     to set the property for.  For direct properties, they are the same type.  For attached
        ///     properties they usually differ. 
        ///  
        public static DependencyPropertyDescriptor FromName(string name, Type ownerType, Type targetType,
            bool ignorePropertyType) 
        {
            if (name == null) throw new ArgumentNullException("name");
            if (ownerType == null) throw new ArgumentNullException("ownerType");
            if (targetType == null) throw new ArgumentNullException("targetType"); 

            DependencyProperty dp = DependencyProperty.FromName(name, ownerType); 
            if (dp != null) 
            {
                if (ignorePropertyType) 
                {
                    try
                    {
                        return FromProperty(dp, ownerType, targetType, ignorePropertyType); 
                    }
                    catch (AmbiguousMatchException) 
                    { 
                        return FromProperty(dp, targetType);
                    } 
                }
                else
                {
                    return FromProperty(dp, targetType); 
                }
            } 
 
            return null;
        } 

        /// 
        ///     Object.Equals override
        ///  
        public override bool Equals(object obj)
        { 
            DependencyPropertyDescriptor dp = obj as DependencyPropertyDescriptor; 
            if (dp != null && dp._dp == _dp && dp._componentType == _componentType)
            { 
                return true;
            }

            return false; 
        }
 
        ///  
        ///     Object.GetHashCode override
        ///  
        public override int GetHashCode()
        {
            return _dp.GetHashCode() ^ _componentType.GetHashCode();
        } 

        ///  
        ///     Object.ToString override 
        /// 
        public override string ToString() 
        {
            return Name;
        }
 
        //
        // The following methods simply route to the underlying property descriptor. 
        // 

        ///  
        ///     When overridden in a derived class, indicates whether
        ///     the property's value can be reset to a default state.
        /// 
        public override bool CanResetValue(object component) { return Property.CanResetValue(component); } 

        ///  
        ///     When overridden in a derived class, gets the current 
        ///     value of the property on a component.
        ///  
        public override object GetValue(object component) { return Property.GetValue(component); }

        /// 
        ///     When overridden in a derived class, resets the 
        ///     value for this property of the component.
        ///  
        public override void ResetValue(object component) { Property.ResetValue(component); } 

        ///  
        ///     When overridden in a derived class, sets the value of
        ///     the component to a different value.
        /// 
        public override void SetValue(object component, object value) { Property.SetValue(component, value); } 

        ///  
        ///     When overridden in a derived class, indicates whether the 
        ///     value of this property needs to be persisted.
        ///  
        public override bool ShouldSerializeValue(object component) { return Property.ShouldSerializeValue(component); }

        /// 
        ///     Allows interested objects to be notified when this property changes. 
        /// 
        public override void AddValueChanged(object component, EventHandler handler) { Property.AddValueChanged(component, handler); } 
 
        /// 
        ///     Allows interested objects to be notified when this property changes. 
        /// 
        public override void RemoveValueChanged(object component, EventHandler handler) { Property.RemoveValueChanged(component, handler); }

        ///  
        ///    Retrieves the properties
        ///  
        public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter) { return Property.GetChildProperties(instance, filter); } 

        ///  
        ///     Gets an editor of the specified type.
        /// 
        public override object GetEditor(Type editorBaseType) { return Property.GetEditor(editorBaseType); }
 

        #endregion Public Methods 
 
        //------------------------------------------------------
        // 
        //  Public Properties
        //
        //-----------------------------------------------------
 
        #region Public Properties
 
        ///  
        ///     Returns the raw dependency property, or null if the property
        ///     this wraps is not a dependency property. 
        /// 
        public DependencyProperty DependencyProperty
        {
            get { return _dp; } 
        }
 
        ///  
        ///     True if the dependency property is being attached to the target type.
        ///  
        public bool IsAttached
        {
            get { return _isAttached; }
        } 

        ///  
        ///     The property metadata for the dependency property.  This can be null if there is 
        ///     no metadata or if there is no dependency property.  Values contained in property
        ///     metadata that have matching concepts in CLR attributes are re-exposed as attributes 
        ///     in the property descriptor's Attributes collection.
        /// 
        public PropertyMetadata Metadata
        { 
            get { return _metadata; }
        } 
 
        //
        // The following properties simply route to the underlying property descriptor. 
        //

        /// 
        ///     When overridden in a derived class, gets the type of the 
        ///     component this property
        ///     is bound to. 
        ///  
        public override Type ComponentType { get { return _componentType; } }
 
        /// 
        ///     When overridden in a derived class, gets a value
        ///     indicating whether this property is read-only.
        ///  
        public override bool IsReadOnly { get { return Property.IsReadOnly; } }
 
        ///  
        ///     When overridden in a derived class,
        ///     gets the type of the property. 
        /// 
        public override Type PropertyType { get { return _dp.PropertyType; } }

        ///  
        ///     Gets the collection of attributes for this member.
        ///  
        public override AttributeCollection Attributes { get { return Property.Attributes; } } 

        ///  
        ///     Gets the name of the category that the
        ///     member belongs to, as specified in the CategoryAttribute.
        /// 
        public override string Category { get { return Property.Category; } } 

        ///  
        ///     Gets the description of 
        ///     the member as specified in the DescriptionAttribute.
        ///  
        public override string Description { get { return Property.Description; } }

        /// 
        ///     Determines whether this member should be set only at 
        ///     design time as specified in the DesignOnlyAttribute.
        ///  
        public override bool DesignTimeOnly { get { return Property.DesignTimeOnly; } } 

        ///  
        ///     Gets the name that can be displayed in a window like a
        ///     properties window.
        /// 
        public override string DisplayName { get { return Property.DisplayName; } } 

        ///  
        ///     Gets the type converter for this property. 
        /// 
        public override TypeConverter Converter 
        {
            get
            {
                // We only support public type converters, in order to avoid asserts. 
                TypeConverter typeConverter = Property.Converter;
                if( typeConverter.GetType().IsPublic ) 
                { 
                    return typeConverter;
                } 
                else
                {
                    return null;
                } 
            }
        } 
 

        ///  
        ///     Gets a value indicating whether the member is browsable as specified in the
        ///     BrowsableAttribute.
        /// 
        public override bool IsBrowsable { get { return Property.IsBrowsable; } } 

        ///  
        ///     Gets a value indicating whether this property should be localized, as 
        ///     specified in the LocalizableAttribute.
        ///  
        public override bool IsLocalizable { get { return Property.IsLocalizable; } }

        /// 
        ///     Indicates whether value change notifications for this property may originate from outside the property 
        ///     descriptor, such as from the component itself (value=true), or whether notifications will only originate
        ///     from direct calls made to PropertyDescriptor.SetValue (value=false). For example, the component may 
        ///     implement the INotifyPropertyChanged interface, or may have an explicit '{name}Changed' event for this property. 
        /// 
        public override bool SupportsChangeEvents { get { return Property.SupportsChangeEvents; } } 

        /// 
        /// 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. 
        ///  
        public CoerceValueCallback DesignerCoerceValueCallback
        { 
            get { return DependencyProperty.DesignerCoerceValueCallback; }
            set { DependencyProperty.DesignerCoerceValueCallback = value; }
        }
 
        #endregion Public Properties
 
 
        //------------------------------------------------------
        // 
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        ///     This method is called when we should clear our cached state.  The cache
        ///     may become invalid if someone adds additional type description providers. 
        /// 
        internal static void ClearCache()
        {
            lock (_cache) 
            {
                _cache.Clear(); 
            } 
        }
 
        #endregion Internal Methods

        //-----------------------------------------------------
        // 
        //  Private Properties
        // 
        //------------------------------------------------------ 

        #region Private Properties 

        // Return the property descriptor we're wrapping.  We may have to get
        // this on demand if it wasn't passed into our constructor
        /// 
        ///     Critical: calls TypeDescriptor.CreateProperty which LinkDemands
        ///     TreatAsSafe: ok to create a property since we should have one anyway 
        /// 
        private PropertyDescriptor Property
        { 
            [SecurityCritical, SecurityTreatAsSafe]
            get
            {
                if (_property == null) 
                {
                    _property = TypeDescriptor.GetProperties(_componentType)[Name]; 
                    if (_property == null) 
                    {
                        // This should not normally happen.  If it does, it means 
                        // that someone has messed around with metadata and has
                        // removed this property from the type's metadata.  We know
                        // that there is really a CLR property, however, because
                        // we are dealing with a direct property (only direct 
                        // properties can have their property descriptor delay
                        // loaded).  So, we can magically create one directly 
                        // from the CLR property through TypeDescriptor. 
                        _property = TypeDescriptor.CreateProperty(_componentType, Name, _dp.PropertyType);
                    } 
                }

                return _property;
            } 
        }
 
        #endregion Private Properties 

        //----------------------------------------------------- 
        //
        //  Private Fields
        //
        //----------------------------------------------------- 

        #region Private Fields 
 
        private PropertyDescriptor _property;
        private Type _componentType; 
        private DependencyProperty _dp;
        private bool _isAttached;
        private PropertyMetadata _metadata;
 
        // Synchronized by "_cache"
        private static Dictionary _cache = 
            new Dictionary( 
                new ReferenceEqualityComparer()
            ); 
        private static Dictionary _ignorePropertyTypeCache =
            new Dictionary(
                new ReferenceEqualityComparer()
            ); 

        #endregion Private Fields 
 
    }
} 


// 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