Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / 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();
}
List newAttributes = 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();
}
List newAttributes = 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
- XamlWriter.cs
- Message.cs
- HttpClientChannel.cs
- ImageAnimator.cs
- DynamicEntity.cs
- CompModHelpers.cs
- XamlStream.cs
- WindowHelperService.cs
- CodeBlockBuilder.cs
- SelectionItemProviderWrapper.cs
- AuthorizationContext.cs
- PriorityQueue.cs
- ActivationServices.cs
- MissingSatelliteAssemblyException.cs
- RegistryKey.cs
- PerfService.cs
- Error.cs
- UnSafeCharBuffer.cs
- SqlDataRecord.cs
- CatalogPartChrome.cs
- QueryExpr.cs
- BufferedReadStream.cs
- OdbcInfoMessageEvent.cs
- CompositeActivityCodeGenerator.cs
- ObjectViewListener.cs
- CLSCompliantAttribute.cs
- TokenizerHelper.cs
- UnionExpr.cs
- RijndaelManaged.cs
- xmlsaver.cs
- ButtonBaseAdapter.cs
- DataGridColumnHeadersPresenter.cs
- Brush.cs
- AnonymousIdentificationModule.cs
- ExpressionBuilderContext.cs
- X509WindowsSecurityToken.cs
- EDesignUtil.cs
- SubstitutionDesigner.cs
- Propagator.ExtentPlaceholderCreator.cs
- HttpWriter.cs
- PassportIdentity.cs
- ToolStripLocationCancelEventArgs.cs
- BitmapMetadataEnumerator.cs
- QilFactory.cs
- CommonGetThemePartSize.cs
- InstanceNormalEvent.cs
- ApplicationSettingsBase.cs
- WebHttpEndpointElement.cs
- ApplicationSecurityManager.cs
- WebPartUtil.cs
- SqlHelper.cs
- MaxMessageSizeStream.cs
- PropertyChangedEventArgs.cs
- SqlMetaData.cs
- RecognizerBase.cs
- safemediahandle.cs
- SortedSet.cs
- BindingCollectionElement.cs
- PropertyNames.cs
- Profiler.cs
- SliderAutomationPeer.cs
- SortableBindingList.cs
- ClrProviderManifest.cs
- OleDbPropertySetGuid.cs
- Inflater.cs
- FragmentQuery.cs
- TextParagraphProperties.cs
- COM2ComponentEditor.cs
- DateTimeConstantAttribute.cs
- RadioButtonList.cs
- Stream.cs
- TextRange.cs
- SerializationFieldInfo.cs
- Utils.cs
- SelfIssuedAuthRSACryptoProvider.cs
- ReliabilityContractAttribute.cs
- Point4D.cs
- TreeViewImageKeyConverter.cs
- DiscoveryExceptionDictionary.cs
- PropagatorResult.cs
- _NTAuthentication.cs
- PerspectiveCamera.cs
- Decimal.cs
- ListView.cs
- FileIOPermission.cs
- SimpleParser.cs
- _ConnectStream.cs
- CodeConstructor.cs
- ProgressChangedEventArgs.cs
- Dispatcher.cs
- WebPartDisplayModeEventArgs.cs
- ContentPlaceHolder.cs
- RoleManagerSection.cs
- StorageMappingItemCollection.cs
- PreviewPrintController.cs
- SequentialUshortCollection.cs
- ComboBoxHelper.cs
- HtmlButton.cs
- DelegateSerializationHolder.cs
- HtmlFormParameterReader.cs