Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / 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); // 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. // 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
- SecurityKeyType.cs
- RequestQueue.cs
- MessageSecurityTokenVersion.cs
- PriorityQueue.cs
- InputQueue.cs
- PropertyInfo.cs
- DocumentGridContextMenu.cs
- DataGridViewComboBoxEditingControl.cs
- Parameter.cs
- StringFormat.cs
- BamlLocalizer.cs
- XamlVector3DCollectionSerializer.cs
- XmlSchemaComplexContentRestriction.cs
- ArithmeticException.cs
- ExportOptions.cs
- WebPartEventArgs.cs
- XPathConvert.cs
- UInt64.cs
- PolyLineSegmentFigureLogic.cs
- TPLETWProvider.cs
- SymbolMethod.cs
- SafePEFileHandle.cs
- IPEndPoint.cs
- NotifyInputEventArgs.cs
- WebPartsPersonalizationAuthorization.cs
- Lease.cs
- ToolStripDropDownClosedEventArgs.cs
- SqlCommandAsyncResult.cs
- diagnosticsswitches.cs
- CustomPopupPlacement.cs
- HtmlForm.cs
- CodeIdentifier.cs
- ping.cs
- _ScatterGatherBuffers.cs
- ProcessHostServerConfig.cs
- InstallerTypeAttribute.cs
- FacetEnabledSchemaElement.cs
- GridToolTip.cs
- StatusCommandUI.cs
- SystemTcpConnection.cs
- HttpValueCollection.cs
- ExtensionDataObject.cs
- Transform.cs
- AllMembershipCondition.cs
- SerializationInfoEnumerator.cs
- WebPartManager.cs
- RectAnimationBase.cs
- BinaryConverter.cs
- ObjectDataSourceChooseMethodsPanel.cs
- LongValidatorAttribute.cs
- TabControlEvent.cs
- SqlMethodCallConverter.cs
- sqlpipe.cs
- TimeSpanMinutesConverter.cs
- ConfigurationElementCollection.cs
- CodeTypeDelegate.cs
- ContextStaticAttribute.cs
- BindingExpression.cs
- WindowsFont.cs
- InputElement.cs
- EntityRecordInfo.cs
- MDIClient.cs
- Vector3DAnimation.cs
- Int32Rect.cs
- ColorConverter.cs
- EnvironmentPermission.cs
- AliasedExpr.cs
- CopyNamespacesAction.cs
- PageSettings.cs
- OutOfProcStateClientManager.cs
- Metadata.cs
- XmlSerializableServices.cs
- SafeNativeMethods.cs
- EncryptedReference.cs
- DateBoldEvent.cs
- Schema.cs
- PackWebResponse.cs
- DataSourceProvider.cs
- MailAddressCollection.cs
- TraceContextRecord.cs
- WriteableBitmap.cs
- storepermissionattribute.cs
- UriExt.cs
- MinMaxParagraphWidth.cs
- SpeakProgressEventArgs.cs
- InputProcessorProfiles.cs
- GeneralTransform3DTo2D.cs
- FormsIdentity.cs
- ReferenceEqualityComparer.cs
- ValidationService.cs
- AssociationTypeEmitter.cs
- PerformanceCounterManager.cs
- TextTreeTextNode.cs
- GraphicsContainer.cs
- WindowsNonControl.cs
- FormattedText.cs
- Touch.cs
- ContextMenuStripActionList.cs
- UserInitiatedRoutedEventPermission.cs
- ReferentialConstraintRoleElement.cs