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

        #region Public Methods

        /// <summary>
        ///     Static method that returns a DependencyPropertyDescriptor from a PropertyDescriptor.
        /// </summary>
        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);
        }
        /// <summary>
        ///     This method is called on demand when we need to get at one or
        ///     more attributes for this property.  Because obtaining attributes
        ///     can be costly, we wait until now to do the job.
        /// </summary>
        private void MergeAttributes() 
        {
            AttributeCollection baseAttributes;

            if (_property != null) 
            {
                baseAttributes = _property.Attributes;
            }
            else 
            {
                baseAttributes = GetAttachedPropertyAttributes();
            }

            List<Attribute> newAttributes = new List<Attribute>(baseAttributes.Count + 1);

            bool readOnly = false;

            foreach (Attribute a in baseAttributes) 
            {
                Attribute attrToAdd = a;
                DefaultValueAttribute defAttr = a as DefaultValueAttribute;

                if (defAttr != null) 
                {
                    // DP metadata always overrides CLR metadata for
                    // default value.
                    attrToAdd = null;
                }
                else 
                {
                    ReadOnlyAttribute roAttr = a as ReadOnlyAttribute;
                    if (roAttr != null)
                    {
                        // DP metata is the merge of CLR metadata for
                        // read only
                        readOnly = roAttr.IsReadOnly;
                        attrToAdd = null;
                    }
                }

                if (attrToAdd != null) newAttributes.Add(attrToAdd);
            }

            // Always include the metadata choice
            readOnly |= _dp.ReadOnly;

            // If we are an attached property and non-read only, the lack of a
            // set method will make us read only.
            if (_property == null && !readOnly && GetAttachedPropertySetMethod(_dp) == null) {
                readOnly = true;
            }

            // Add our own DependencyPropertyAttribute
            DependencyPropertyAttribute dpa = new DependencyPropertyAttribute(_dp, (_property == null));
            newAttributes.Add(dpa);

            // Add DefaultValueAttribute if the DP has a default
            // value
            if (_metadata.DefaultValue != DependencyProperty.UnsetValue) 
            {
                newAttributes.Add(new DefaultValueAttribute(_metadata.DefaultValue));
            }

            // And add a read only attribute if needed
            if (readOnly) 
            {
                newAttributes.Add(new ReadOnlyAttribute(true));
            }

            // Inject these attributes into our attribute array.  There
            // is a quirk to the way this works.  Attributes as they
            // are returned by the CLR and by AttributeCollection are in
            // priority order with the attributes at the front of the list
            // taking precidence over those at the end.  Attributes
            // handed to MemberDescriptor's AttributeArray, however, are
            // in reverse priority order so the "last one in wins".  Therefore
            // we need to reverse the array.

            Attribute[] attrArray = newAttributes.ToArray();
            for (int idx = 0; idx < attrArray.Length / 2; idx++) 
            {
                int swap = attrArray.Length - idx - 1;
                Attribute t = attrArray[idx];
                attrArray[idx] = attrArray[swap];
                attrArray[swap] = t;
            }

            AttributeArray = attrArray;
        }
        DependencyPropertyInfo GetDependencyPropertyInfo(PropertyInfo property, DependencyPropertyAttribute attribute)
        {
            if (_enforceWpfConvention)
            {
                // Find public dependency property field identifier.
                const BindingFlags identifierModifiers = BindingFlags.Public | BindingFlags.Static;
                string             identifierField     = property.Name + IdentifierSuffix;
                FieldInfo          identifier          = OwnerType.GetField(identifierField, identifierModifiers);
                if (identifier == null || (identifier.FieldType != typeof(DependencyProperty)))
                {
                    throw new InvalidImplementationException(
                              ConventionEnabledError +
                              "There is no public static dependency property field identifier \"" + identifierField +
                              "\" available in the class \"" + OwnerType.Name + "\".");
                }

                // Verify name when set.
                if (attribute.Name != null && property.Name != attribute.Name)
                {
                    throw new InvalidImplementationException(
                              ConventionEnabledError + "The CLR property wrapper '" + property.Name +
                              "' doesn't match the name of the dependency property.");
                }
            }

            // Set dependency property parameters.
            Type       propertyType = property.PropertyType;
            MethodInfo setMethod    = property.GetSetMethod();
            object     defaultValue;

            if (attribute.DefaultValueProvider != null)
            {
                var defaultValueProvider = (IDefaultValueProvider <T>)Activator.CreateInstance(attribute.DefaultValueProvider);
                defaultValue = defaultValueProvider.GetDefaultValue((T)attribute.GetId(), property.PropertyType);
            }
            else
            {
                defaultValue = attribute.DefaultValue ?? propertyType.CreateDefault();
            }
            if (defaultValue != null && defaultValue.GetType() != propertyType)
            {
                TypeConverter converter = TypeDescriptor.GetConverter(propertyType);
                if (converter.CanConvertFrom(defaultValue.GetType()))
                {
                    var context = new TypeDescriptorContext(propertyType);
                    defaultValue = converter.ConvertFrom(context, CultureInfo.CurrentCulture, defaultValue);
                }
            }
            var metaData = new FrameworkPropertyMetadata
            {
                DefaultValue                   = defaultValue,
                AffectsArrange                 = attribute.AffectsArrange,
                AffectsMeasure                 = attribute.AffectsMeasure,
                AffectsParentArrange           = attribute.AffectsParentArrange,
                AffectsParentMeasure           = attribute.AffectsParentMeasure,
                AffectsRender                  = attribute.AffectsRender,
                SubPropertiesDoNotAffectRender = attribute.SubPropertiesDoNotAffectRender
            };
            var dependencyPropertyInfo = new DependencyPropertyInfo
            {
                IsAttached = false,
                Name       = attribute.Name ?? property.Name,
                Type       = propertyType,
                // When no default value is set, use the default value.
                MetaData = metaData,
                // By default, readonly when setter is private.
                ReadOnly = attribute.IsReadOnlySet() ? attribute.IsReadOnly() : (setMethod == null || setMethod.IsPrivate),
                Id       = (T)attribute.GetId()
            };

            return(dependencyPropertyInfo);
        }