Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Base / MS / Internal / ComponentModel / DependencyObjectPropertyDescriptor.cs / 1 / DependencyObjectPropertyDescriptor.cs
namespace MS.Internal.ComponentModel { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Security.Permissions; using System.Windows; using System.Security; ////// An inplementation of a property descriptor for DependencyProperties. /// This supports both normal and attached properties. /// internal sealed class DependencyObjectPropertyDescriptor : 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 takes 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. /// internal DependencyObjectPropertyDescriptor(PropertyDescriptor property, DependencyProperty dp, Type objectType) : base(dp.Name, null) { _property = property; _dp = dp; Debug.Assert(property != null && dp != null); Debug.Assert(!(property is DependencyObjectPropertyDescriptor), "Wrapping a DP in a DP"); _componentType = property.ComponentType; _metadata = _dp.GetMetadata(objectType); } ////// 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 takes 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. /// internal DependencyObjectPropertyDescriptor(DependencyProperty dp, Type ownerType) : base(string.Concat(dp.OwnerType.Name, ".", dp.Name), null) { _dp = dp; _componentType = ownerType; _metadata = _dp.GetMetadata(ownerType); } #endregion Constructors //----------------------------------------------------- // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Indicates if this property's value can be reset. /// We map this to true if there is a local value /// on the DP. /// public override bool CanResetValue(object component) { // All DPs that have values set can be reset return ShouldSerializeValue(component); } ////// Returns the value for this property. /// public override object GetValue(object component) { DependencyObject DO = FromObj(component); return DO.GetValue(_dp); } ////// Attempts to reset (or clear) the value in the /// DP. /// public override void ResetValue(object component) { if (!_queriedResetMethod) { _resetMethod = GetSpecialMethod("Reset"); _queriedResetMethod = true; } DependencyObject DO = FromObj(component); if (_resetMethod != null) { // See if we need to pass parameters to this method. When // _property == null, this is an attached property and // the method is static. When _property != null, this // is a direct property and the method is instanced. if (_property == null) { _resetMethod.Invoke(null, new object[] {DO}); } else { _resetMethod.Invoke(DO, null); } } else { DO.ClearValue(_dp); } } ////// Sets the property value on the given object. /// public override void SetValue(object component, object value) { DependencyObject DO = FromObj(component); DO.SetValue(_dp, value); } ////// Returns true if the property contains /// a local value that should be serialized. /// public override bool ShouldSerializeValue(object component) { DependencyObject DO = FromObj(component); bool shouldSerialize = DO.ShouldSerializeProperty(_dp); // The of precedence is that a property should be serialized if the ShouldSerializeProperty // method returns true and either ShouldSerializeXXX does not exist or it exists and returns true. if (shouldSerialize) { // If we have a ShouldSerialize method, use it if (!_queriedShouldSerializeMethod) { MethodInfo method = GetSpecialMethod("ShouldSerialize"); if (method != null && method.ReturnType == typeof(bool)) { _shouldSerializeMethod = method; } _queriedShouldSerializeMethod = true; } if (_shouldSerializeMethod != null) { // See if we need to pass parameters to this method. When // _property == null, this is an attached property and // the method is static. When _property != null, this // is a direct property and the method is instanced. if (_property == null) { shouldSerialize = (bool)_shouldSerializeMethod.Invoke(null, new object[] {DO}); } else { shouldSerialize = (bool)_shouldSerializeMethod.Invoke(DO, null); } } } return shouldSerialize; } ////// Adds a change event handler to this descriptor. /// public override void AddValueChanged(object component, EventHandler handler) { // DependencyObject DO = FromObj(component); if (_trackers == null) { _trackers = new Dictionary(); } PropertyChangeTracker tracker; if (!_trackers.TryGetValue(DO, out tracker)) { tracker = new PropertyChangeTracker(DO, _dp); _trackers.Add(DO, tracker); } tracker.Changed += handler; } /// /// Removes a previously added change handler. /// public override void RemoveValueChanged(object component, EventHandler handler) { if (_trackers == null) return; PropertyChangeTracker tracker; DependencyObject DO = FromObj(component); if (_trackers.TryGetValue(DO, out tracker)) { tracker.Changed -= handler; if (tracker.CanClose) { tracker.Close(); _trackers.Remove(DO); } } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties ////// Returns the collection of attributes associated with this property. /// public override AttributeCollection Attributes { get { // Windows OS Bugs 1383847. The Attributes // property on PropertyDescriptor is not as thread // safe as it should be. There are instances when // it can return null during contention. Our fix is // to detect this case and lock. Note that this isn't // 100% because not all property descriptors are // DependencyObjectPropertyDescriptors. AttributeCollection attrs = base.Attributes; if (attrs == null) { lock(_attributeSyncLock) { attrs = base.Attributes; Debug.Assert(attrs != null); } } return attrs; } } ////// The type of object this property is describing. /// public override Type ComponentType { get { return _componentType; } } ////// Returns true if the DP is read only. /// public override bool IsReadOnly { get { // It is a lot cheaper to get DP metadata // than it is to calculate attributes. While // the attributes do factor in DP metadata, short // circuit for this common case. bool readOnly = _dp.ReadOnly; if (!readOnly) { readOnly = Attributes.Contains(ReadOnlyAttribute.Yes); } return readOnly; } } ////// The type of the property. /// public override Type PropertyType { get { return _dp.PropertyType; } } ////// Returns true if this property descriptor supports change /// notifications. All dependency property descriptors do. /// public override bool SupportsChangeEvents { get { return true; } } #endregion Public Properties //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Returns the dependency property we're wrapping. /// internal DependencyProperty DependencyProperty { get { return _dp; } } internal bool IsAttached { get { return (_property == null); } } internal PropertyMetadata Metadata { get { return _metadata; } } #endregion Internal 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 (_getMethodCache) { _getMethodCache.Clear(); } lock(_setMethodCache) { _setMethodCache.Clear(); } } ////// A helper method that returns the static "Get" method for an attached /// property. The dpType parameter is the data type of the object you /// want to attach the property to. /// internal static MethodInfo GetAttachedPropertyMethod(DependencyProperty dp) { // Check the cache. This property descriptor is cached by the // dependency object provider, but there is a unique property descriptor // for each type an attached property can be attached to. Therefore, // caching this method lookup for a DP makes sense. MethodInfo method; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywhere // we rely on raw reflection we should be using GetReflectionType. // Also the returning type may change if someone added or removed // a provider, so we need to detect this in our cache invalidation // logic. Type reflectionType = TypeDescriptor.GetReflectionType(dp.OwnerType); object methodObj = _getMethodCache[dp]; method = methodObj as MethodInfo; if (methodObj == null || (method != null && !object.ReferenceEquals(method.DeclaringType, reflectionType))) { BindingFlags f = BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly; string methodName = string.Concat("Get", dp.Name); method = reflectionType.GetMethod(methodName, f, _dpBinder, _dpType, null); lock(_getMethodCache) { _getMethodCache[dp] = (method == null ? _nullMethodSentinel : method); } } return method; } #endregion Internal Methods //----------------------------------------------------- // // Protected Methods // //----------------------------------------------------- #region Protected Methods ////// Overridden to lazily create our attributes. /// protected override AttributeCollection CreateAttributeCollection() { MergeAttributes(); return base.CreateAttributeCollection(); } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Helper method that recovers a dependency object from a value. /// private static DependencyObject FromObj(object value) { // This indirection is necessary to support // the "association" feature of type descriptor. This feature // alows one object to mimic the API of another. return (DependencyObject)TypeDescriptor.GetAssociation(typeof(DependencyObject), value); } ////// Additional metadata attributes for attached properties /// are taken from the "Get" method. /// private AttributeCollection GetAttachedPropertyAttributes() { MethodInfo mi = GetAttachedPropertyMethod(_dp); if (mi != null) { Attribute[] attrArray = (Attribute[])mi.GetCustomAttributes(typeof(Attribute), true); Type propertyReflectionType = TypeDescriptor.GetReflectionType(_dp.PropertyType); Attribute[] typeAttrArray = (Attribute[])propertyReflectionType.GetCustomAttributes(typeof(Attribute), true); if (typeAttrArray != null && typeAttrArray.Length > 0) { // Merge attrArry and typeAttrArray Attribute[] mergedAttrArray = new Attribute[attrArray.Length + typeAttrArray.Length]; Array.Copy(attrArray, mergedAttrArray, attrArray.Length); Array.Copy(typeAttrArray, 0, mergedAttrArray, attrArray.Length, typeAttrArray.Length); attrArray = mergedAttrArray; } // Look for and expand AttributeProvider attributes. These are attributes // that allow a method to adopt attributes from another location. This // allows generic properties, such as "public object DataSource {get; set;}", // to share a common set of attributes. Attribute[] addAttrs = null; foreach(Attribute attr in attrArray) { AttributeProviderAttribute pa = attr as AttributeProviderAttribute; if (pa != null) { Type providerType = Type.GetType(pa.TypeName); if (providerType != null) { Attribute[] paAttrs = null; if (!string.IsNullOrEmpty(pa.PropertyName)) { MemberInfo[] milist = providerType.GetMember(pa.PropertyName); if (milist.Length > 0 && milist[0] != null) { paAttrs = (Attribute[])milist[0].GetCustomAttributes(typeof(Attribute), true); } } else { paAttrs = (Attribute[])providerType.GetCustomAttributes(typeof(Attribute), true); } if (paAttrs != null) { if (addAttrs == null) { addAttrs = paAttrs; } else { Attribute[] newArray = new Attribute[addAttrs.Length + paAttrs.Length]; addAttrs.CopyTo(newArray, 0); paAttrs.CopyTo(newArray, addAttrs.Length); addAttrs = newArray; } } } } } // See if we gathered additional attributes. These are always lower priority // and therefore get tacked onto the end of the list if (addAttrs != null) { Attribute[] newArray = new Attribute[addAttrs.Length + attrArray.Length]; attrArray.CopyTo(newArray, 0); addAttrs.CopyTo(newArray, attrArray.Length); attrArray = newArray; } return new AttributeCollection(attrArray); } return AttributeCollection.Empty; } ////// A helper method that returns the static "Get" method for an attached /// property. The dpType parameter is the data type of the object you /// want to attach the property to. /// private static MethodInfo GetAttachedPropertySetMethod(DependencyProperty dp) { // Check the cache. This property descriptor is cached by the // dependency object provider, but there is a unique property descriptor // for each type an attached property can be attached to. Therefore, // caching this method lookup for a DP makes sense. MethodInfo method; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywhere // we rely on raw reflection we should be using GetReflectionType. // Also the returning type may change if someone added or removed // a provider, so we need to detect this in our cache invalidation // logic. Type reflectionType = TypeDescriptor.GetReflectionType(dp.OwnerType); object methodObj = _setMethodCache[dp]; method = methodObj as MethodInfo; if (methodObj == null || (method != null && !object.ReferenceEquals(method.DeclaringType, reflectionType))) { BindingFlags f = BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly; string methodName = string.Concat("Set", dp.Name); Type[] paramTypes = new Type[] { typeof(DependencyObject), dp.PropertyType }; method = reflectionType.GetMethod(methodName, f, _dpBinder, paramTypes, null); lock(_setMethodCache) { _setMethodCache[dp] = (method == null ? _nullMethodSentinel : method); } } return method; } ////// Returns one of the "special" property methods for a property descriptor. /// The property name will be appended to the method prefix. This method /// is used to return the MethodInfo for ShouldSerialize(property) and /// Reset(property). /// private MethodInfo GetSpecialMethod(string methodPrefix) { BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic; Type[] types; Type reflectionType; if (_property == null) { // Attached property types = _dpType; flags |= BindingFlags.Static; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywyere // we rely on raw reflection we should be using GetReflectionType. reflectionType = TypeDescriptor.GetReflectionType(_dp.OwnerType); } else { // Direct property types = _emptyType; flags |= BindingFlags.Instance; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywyere // we rely on raw reflection we should be using GetReflectionType. reflectionType = TypeDescriptor.GetReflectionType(_property.ComponentType); } string methodName = string.Concat(methodPrefix, _dp.Name); // According to spec, ShouldSerialize and Reset can be non-public. So we should // assert ReflectionPermission here, like TypeDescriptor does. But since every // assert is a security risk, we'll take the compatibility hit, and leave it out. MethodInfo methodInfo = reflectionType.GetMethod(methodName, flags, _dpBinder, types, null); if (methodInfo != null) { // We don't support non-public ShouldSerialize/ClearValue methods. We could just look // for public methods in the first place, but then authors might get confused as // to why their non-public method didn't get found, especially because the CLR // TypeDescriptor does find and use non-public methods. if( !methodInfo.IsPublic ) { throw new InvalidOperationException(SR.Get(SRID.SpecialMethodMustBePublic, methodInfo.Name)); } } return methodInfo; } ////// 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. /// private void MergeAttributes() { AttributeCollection baseAttributes; if (_property != null) { baseAttributes = _property.Attributes; } else { baseAttributes = GetAttachedPropertyAttributes(); } ListnewAttributes = new List (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; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private static Type[] _emptyType = new Type[0]; private static Type[] _dpType = new Type[] {typeof(DependencyObject)}; private static Binder _dpBinder = new AttachedPropertyMethodSelector(); private static object _nullMethodSentinel = new object(); // Synchronized by "_getMethodCache" private static Hashtable _getMethodCache = new Hashtable(); // Synchronized by "_setMethodCache" private static Hashtable _setMethodCache = new Hashtable(); // Synchronization object for Attributes property. This would be better to be a // member than a static value, but the need for a lock on Attributes is very // rare and isn't worth the additional space this would take up as a member private static object _attributeSyncLock = new object(); private PropertyDescriptor _property; private DependencyProperty _dp; private Type _componentType; private PropertyMetadata _metadata; private MethodInfo _shouldSerializeMethod; private MethodInfo _resetMethod; private bool _queriedShouldSerializeMethod; private bool _queriedResetMethod; private Dictionary _trackers; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. namespace MS.Internal.ComponentModel { using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Security.Permissions; using System.Windows; using System.Security; /// /// An inplementation of a property descriptor for DependencyProperties. /// This supports both normal and attached properties. /// internal sealed class DependencyObjectPropertyDescriptor : 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 takes 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. /// internal DependencyObjectPropertyDescriptor(PropertyDescriptor property, DependencyProperty dp, Type objectType) : base(dp.Name, null) { _property = property; _dp = dp; Debug.Assert(property != null && dp != null); Debug.Assert(!(property is DependencyObjectPropertyDescriptor), "Wrapping a DP in a DP"); _componentType = property.ComponentType; _metadata = _dp.GetMetadata(objectType); } ////// 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 takes 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. /// internal DependencyObjectPropertyDescriptor(DependencyProperty dp, Type ownerType) : base(string.Concat(dp.OwnerType.Name, ".", dp.Name), null) { _dp = dp; _componentType = ownerType; _metadata = _dp.GetMetadata(ownerType); } #endregion Constructors //----------------------------------------------------- // // Public Methods // //----------------------------------------------------- #region Public Methods ////// Indicates if this property's value can be reset. /// We map this to true if there is a local value /// on the DP. /// public override bool CanResetValue(object component) { // All DPs that have values set can be reset return ShouldSerializeValue(component); } ////// Returns the value for this property. /// public override object GetValue(object component) { DependencyObject DO = FromObj(component); return DO.GetValue(_dp); } ////// Attempts to reset (or clear) the value in the /// DP. /// public override void ResetValue(object component) { if (!_queriedResetMethod) { _resetMethod = GetSpecialMethod("Reset"); _queriedResetMethod = true; } DependencyObject DO = FromObj(component); if (_resetMethod != null) { // See if we need to pass parameters to this method. When // _property == null, this is an attached property and // the method is static. When _property != null, this // is a direct property and the method is instanced. if (_property == null) { _resetMethod.Invoke(null, new object[] {DO}); } else { _resetMethod.Invoke(DO, null); } } else { DO.ClearValue(_dp); } } ////// Sets the property value on the given object. /// public override void SetValue(object component, object value) { DependencyObject DO = FromObj(component); DO.SetValue(_dp, value); } ////// Returns true if the property contains /// a local value that should be serialized. /// public override bool ShouldSerializeValue(object component) { DependencyObject DO = FromObj(component); bool shouldSerialize = DO.ShouldSerializeProperty(_dp); // The of precedence is that a property should be serialized if the ShouldSerializeProperty // method returns true and either ShouldSerializeXXX does not exist or it exists and returns true. if (shouldSerialize) { // If we have a ShouldSerialize method, use it if (!_queriedShouldSerializeMethod) { MethodInfo method = GetSpecialMethod("ShouldSerialize"); if (method != null && method.ReturnType == typeof(bool)) { _shouldSerializeMethod = method; } _queriedShouldSerializeMethod = true; } if (_shouldSerializeMethod != null) { // See if we need to pass parameters to this method. When // _property == null, this is an attached property and // the method is static. When _property != null, this // is a direct property and the method is instanced. if (_property == null) { shouldSerialize = (bool)_shouldSerializeMethod.Invoke(null, new object[] {DO}); } else { shouldSerialize = (bool)_shouldSerializeMethod.Invoke(DO, null); } } } return shouldSerialize; } ////// Adds a change event handler to this descriptor. /// public override void AddValueChanged(object component, EventHandler handler) { // DependencyObject DO = FromObj(component); if (_trackers == null) { _trackers = new Dictionary(); } PropertyChangeTracker tracker; if (!_trackers.TryGetValue(DO, out tracker)) { tracker = new PropertyChangeTracker(DO, _dp); _trackers.Add(DO, tracker); } tracker.Changed += handler; } /// /// Removes a previously added change handler. /// public override void RemoveValueChanged(object component, EventHandler handler) { if (_trackers == null) return; PropertyChangeTracker tracker; DependencyObject DO = FromObj(component); if (_trackers.TryGetValue(DO, out tracker)) { tracker.Changed -= handler; if (tracker.CanClose) { tracker.Close(); _trackers.Remove(DO); } } } #endregion Public Methods //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties ////// Returns the collection of attributes associated with this property. /// public override AttributeCollection Attributes { get { // Windows OS Bugs 1383847. The Attributes // property on PropertyDescriptor is not as thread // safe as it should be. There are instances when // it can return null during contention. Our fix is // to detect this case and lock. Note that this isn't // 100% because not all property descriptors are // DependencyObjectPropertyDescriptors. AttributeCollection attrs = base.Attributes; if (attrs == null) { lock(_attributeSyncLock) { attrs = base.Attributes; Debug.Assert(attrs != null); } } return attrs; } } ////// The type of object this property is describing. /// public override Type ComponentType { get { return _componentType; } } ////// Returns true if the DP is read only. /// public override bool IsReadOnly { get { // It is a lot cheaper to get DP metadata // than it is to calculate attributes. While // the attributes do factor in DP metadata, short // circuit for this common case. bool readOnly = _dp.ReadOnly; if (!readOnly) { readOnly = Attributes.Contains(ReadOnlyAttribute.Yes); } return readOnly; } } ////// The type of the property. /// public override Type PropertyType { get { return _dp.PropertyType; } } ////// Returns true if this property descriptor supports change /// notifications. All dependency property descriptors do. /// public override bool SupportsChangeEvents { get { return true; } } #endregion Public Properties //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties ////// Returns the dependency property we're wrapping. /// internal DependencyProperty DependencyProperty { get { return _dp; } } internal bool IsAttached { get { return (_property == null); } } internal PropertyMetadata Metadata { get { return _metadata; } } #endregion Internal 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 (_getMethodCache) { _getMethodCache.Clear(); } lock(_setMethodCache) { _setMethodCache.Clear(); } } ////// A helper method that returns the static "Get" method for an attached /// property. The dpType parameter is the data type of the object you /// want to attach the property to. /// internal static MethodInfo GetAttachedPropertyMethod(DependencyProperty dp) { // Check the cache. This property descriptor is cached by the // dependency object provider, but there is a unique property descriptor // for each type an attached property can be attached to. Therefore, // caching this method lookup for a DP makes sense. MethodInfo method; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywhere // we rely on raw reflection we should be using GetReflectionType. // Also the returning type may change if someone added or removed // a provider, so we need to detect this in our cache invalidation // logic. Type reflectionType = TypeDescriptor.GetReflectionType(dp.OwnerType); object methodObj = _getMethodCache[dp]; method = methodObj as MethodInfo; if (methodObj == null || (method != null && !object.ReferenceEquals(method.DeclaringType, reflectionType))) { BindingFlags f = BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly; string methodName = string.Concat("Get", dp.Name); method = reflectionType.GetMethod(methodName, f, _dpBinder, _dpType, null); lock(_getMethodCache) { _getMethodCache[dp] = (method == null ? _nullMethodSentinel : method); } } return method; } #endregion Internal Methods //----------------------------------------------------- // // Protected Methods // //----------------------------------------------------- #region Protected Methods ////// Overridden to lazily create our attributes. /// protected override AttributeCollection CreateAttributeCollection() { MergeAttributes(); return base.CreateAttributeCollection(); } #endregion Protected Methods //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods ////// Helper method that recovers a dependency object from a value. /// private static DependencyObject FromObj(object value) { // This indirection is necessary to support // the "association" feature of type descriptor. This feature // alows one object to mimic the API of another. return (DependencyObject)TypeDescriptor.GetAssociation(typeof(DependencyObject), value); } ////// Additional metadata attributes for attached properties /// are taken from the "Get" method. /// private AttributeCollection GetAttachedPropertyAttributes() { MethodInfo mi = GetAttachedPropertyMethod(_dp); if (mi != null) { Attribute[] attrArray = (Attribute[])mi.GetCustomAttributes(typeof(Attribute), true); Type propertyReflectionType = TypeDescriptor.GetReflectionType(_dp.PropertyType); Attribute[] typeAttrArray = (Attribute[])propertyReflectionType.GetCustomAttributes(typeof(Attribute), true); if (typeAttrArray != null && typeAttrArray.Length > 0) { // Merge attrArry and typeAttrArray Attribute[] mergedAttrArray = new Attribute[attrArray.Length + typeAttrArray.Length]; Array.Copy(attrArray, mergedAttrArray, attrArray.Length); Array.Copy(typeAttrArray, 0, mergedAttrArray, attrArray.Length, typeAttrArray.Length); attrArray = mergedAttrArray; } // Look for and expand AttributeProvider attributes. These are attributes // that allow a method to adopt attributes from another location. This // allows generic properties, such as "public object DataSource {get; set;}", // to share a common set of attributes. Attribute[] addAttrs = null; foreach(Attribute attr in attrArray) { AttributeProviderAttribute pa = attr as AttributeProviderAttribute; if (pa != null) { Type providerType = Type.GetType(pa.TypeName); if (providerType != null) { Attribute[] paAttrs = null; if (!string.IsNullOrEmpty(pa.PropertyName)) { MemberInfo[] milist = providerType.GetMember(pa.PropertyName); if (milist.Length > 0 && milist[0] != null) { paAttrs = (Attribute[])milist[0].GetCustomAttributes(typeof(Attribute), true); } } else { paAttrs = (Attribute[])providerType.GetCustomAttributes(typeof(Attribute), true); } if (paAttrs != null) { if (addAttrs == null) { addAttrs = paAttrs; } else { Attribute[] newArray = new Attribute[addAttrs.Length + paAttrs.Length]; addAttrs.CopyTo(newArray, 0); paAttrs.CopyTo(newArray, addAttrs.Length); addAttrs = newArray; } } } } } // See if we gathered additional attributes. These are always lower priority // and therefore get tacked onto the end of the list if (addAttrs != null) { Attribute[] newArray = new Attribute[addAttrs.Length + attrArray.Length]; attrArray.CopyTo(newArray, 0); addAttrs.CopyTo(newArray, attrArray.Length); attrArray = newArray; } return new AttributeCollection(attrArray); } return AttributeCollection.Empty; } ////// A helper method that returns the static "Get" method for an attached /// property. The dpType parameter is the data type of the object you /// want to attach the property to. /// private static MethodInfo GetAttachedPropertySetMethod(DependencyProperty dp) { // Check the cache. This property descriptor is cached by the // dependency object provider, but there is a unique property descriptor // for each type an attached property can be attached to. Therefore, // caching this method lookup for a DP makes sense. MethodInfo method; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywhere // we rely on raw reflection we should be using GetReflectionType. // Also the returning type may change if someone added or removed // a provider, so we need to detect this in our cache invalidation // logic. Type reflectionType = TypeDescriptor.GetReflectionType(dp.OwnerType); object methodObj = _setMethodCache[dp]; method = methodObj as MethodInfo; if (methodObj == null || (method != null && !object.ReferenceEquals(method.DeclaringType, reflectionType))) { BindingFlags f = BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly; string methodName = string.Concat("Set", dp.Name); Type[] paramTypes = new Type[] { typeof(DependencyObject), dp.PropertyType }; method = reflectionType.GetMethod(methodName, f, _dpBinder, paramTypes, null); lock(_setMethodCache) { _setMethodCache[dp] = (method == null ? _nullMethodSentinel : method); } } return method; } ////// Returns one of the "special" property methods for a property descriptor. /// The property name will be appended to the method prefix. This method /// is used to return the MethodInfo for ShouldSerialize(property) and /// Reset(property). /// private MethodInfo GetSpecialMethod(string methodPrefix) { BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic; Type[] types; Type reflectionType; if (_property == null) { // Attached property types = _dpType; flags |= BindingFlags.Static; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywyere // we rely on raw reflection we should be using GetReflectionType. reflectionType = TypeDescriptor.GetReflectionType(_dp.OwnerType); } else { // Direct property types = _emptyType; flags |= BindingFlags.Instance; // TypeDescriptor offers a feature called a "reflection type", which // is an indirection to another type we should reflect on. Anywyere // we rely on raw reflection we should be using GetReflectionType. reflectionType = TypeDescriptor.GetReflectionType(_property.ComponentType); } string methodName = string.Concat(methodPrefix, _dp.Name); // According to spec, ShouldSerialize and Reset can be non-public. So we should // assert ReflectionPermission here, like TypeDescriptor does. But since every // assert is a security risk, we'll take the compatibility hit, and leave it out. MethodInfo methodInfo = reflectionType.GetMethod(methodName, flags, _dpBinder, types, null); if (methodInfo != null) { // We don't support non-public ShouldSerialize/ClearValue methods. We could just look // for public methods in the first place, but then authors might get confused as // to why their non-public method didn't get found, especially because the CLR // TypeDescriptor does find and use non-public methods. if( !methodInfo.IsPublic ) { throw new InvalidOperationException(SR.Get(SRID.SpecialMethodMustBePublic, methodInfo.Name)); } } return methodInfo; } ////// 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. /// private void MergeAttributes() { AttributeCollection baseAttributes; if (_property != null) { baseAttributes = _property.Attributes; } else { baseAttributes = GetAttachedPropertyAttributes(); } ListnewAttributes = new List (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; } #endregion Private Methods //----------------------------------------------------- // // Private Fields // //------------------------------------------------------ #region Private Fields private static Type[] _emptyType = new Type[0]; private static Type[] _dpType = new Type[] {typeof(DependencyObject)}; private static Binder _dpBinder = new AttachedPropertyMethodSelector(); private static object _nullMethodSentinel = new object(); // Synchronized by "_getMethodCache" private static Hashtable _getMethodCache = new Hashtable(); // Synchronized by "_setMethodCache" private static Hashtable _setMethodCache = new Hashtable(); // Synchronization object for Attributes property. This would be better to be a // member than a static value, but the need for a lock on Attributes is very // rare and isn't worth the additional space this would take up as a member private static object _attributeSyncLock = new object(); private PropertyDescriptor _property; private DependencyProperty _dp; private Type _componentType; private PropertyMetadata _metadata; private MethodInfo _shouldSerializeMethod; private MethodInfo _resetMethod; private bool _queriedShouldSerializeMethod; private bool _queriedResetMethod; private Dictionary _trackers; #endregion Private Fields } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- JapaneseCalendar.cs
- WindowsPen.cs
- log.cs
- OperationFormatUse.cs
- WebZoneDesigner.cs
- PerformanceCounterPermissionEntry.cs
- CoreSwitches.cs
- FixedTextSelectionProcessor.cs
- ContentTextAutomationPeer.cs
- ListViewItemMouseHoverEvent.cs
- Membership.cs
- EffectiveValueEntry.cs
- ConditionalAttribute.cs
- EntitySqlQueryCacheEntry.cs
- UIntPtr.cs
- ImmutableAssemblyCacheEntry.cs
- XsdDuration.cs
- PlainXmlDeserializer.cs
- SqlClientPermission.cs
- TypeCodeDomSerializer.cs
- AsymmetricAlgorithm.cs
- NameValuePair.cs
- WebPartChrome.cs
- AccessDataSourceView.cs
- ReadOnlyDataSourceView.cs
- Part.cs
- AttributeSetAction.cs
- OpenTypeLayout.cs
- WindowsScroll.cs
- SelectQueryOperator.cs
- ScriptControl.cs
- ObjectSet.cs
- XamlParser.cs
- SecurityHelper.cs
- ListView.cs
- LookupNode.cs
- HttpHandlerActionCollection.cs
- TextAdaptor.cs
- NonClientArea.cs
- SqlDependencyUtils.cs
- Exceptions.cs
- EntityTypeBase.cs
- SqlVersion.cs
- PasswordTextNavigator.cs
- DbTransaction.cs
- DbExpressionVisitor.cs
- SynchronizationValidator.cs
- FunctionImportElement.cs
- HttpRuntimeSection.cs
- LinqDataSourceInsertEventArgs.cs
- MarginCollapsingState.cs
- ResourceCategoryAttribute.cs
- WS2007HttpBindingCollectionElement.cs
- WSDualHttpBindingCollectionElement.cs
- MouseBinding.cs
- BStrWrapper.cs
- HttpCookieCollection.cs
- TrackingMemoryStream.cs
- ComboBox.cs
- Base64Stream.cs
- WeakReadOnlyCollection.cs
- Path.cs
- XPathNavigatorReader.cs
- MemberAssignmentAnalysis.cs
- TextTabProperties.cs
- Canvas.cs
- UserControlCodeDomTreeGenerator.cs
- RectValueSerializer.cs
- StyleReferenceConverter.cs
- TemplateNameScope.cs
- LiteralTextParser.cs
- NonClientArea.cs
- Identifier.cs
- ExceptionUtil.cs
- ParameterCollection.cs
- TraceHandlerErrorFormatter.cs
- PointConverter.cs
- InputProcessorProfilesLoader.cs
- ExceptionUtil.cs
- TableItemStyle.cs
- ConfigXmlWhitespace.cs
- SqlCacheDependency.cs
- UriSection.cs
- ViewManager.cs
- ProcessThreadCollection.cs
- ExternalException.cs
- RouteParametersHelper.cs
- GeometryDrawing.cs
- IdleTimeoutMonitor.cs
- InfoCardRSAPKCS1SignatureFormatter.cs
- EntityContainerEmitter.cs
- DrawingAttributeSerializer.cs
- GridViewCellAutomationPeer.cs
- NewItemsContextMenuStrip.cs
- DecoderReplacementFallback.cs
- PingOptions.cs
- _AutoWebProxyScriptEngine.cs
- Walker.cs
- GenericsInstances.cs
- ModelTreeManager.cs