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