The Labs \ Source Viewer \ SSCLI \ System.ComponentModel \ PropertyDescriptor

  1. //------------------------------------------------------------------------------
  2. // <copyright file="PropertyDescriptor.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*
  16. */
  17. [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2113:SecureLateBindingMethods", Scope = "member", Target = "System.ComponentModel.PropertyDescriptor.GetTypeFromName(System.String):System.Type")]
  18. namespace System.ComponentModel
  19. {
  20.    
  21.     using Microsoft.Win32;
  22.     using System;
  23.     using System.Collections;
  24.     using System.ComponentModel.Design;
  25.     using System.Diagnostics;
  26.     using System.Reflection;
  27.     using System.Runtime.InteropServices;
  28.     using System.Runtime.Remoting.Activation;
  29.     using System.Runtime.Serialization.Formatters;
  30.     using System.Security;
  31.     using System.Security.Permissions;
  32.    
  33.     /// <devdoc>
  34.     /// <para>Provides a description of a property.</para>
  35.     /// </devdoc>
  36.     [HostProtection(SharedState = true)]
  37.     [System.Runtime.InteropServices.ComVisible(true)]
  38.     public abstract class PropertyDescriptor : MemberDescriptor
  39.     {
  40.         private TypeConverter converter = null;
  41.         private Hashtable valueChangedHandlers;
  42.         private object[] editors;
  43.         private Type[] editorTypes;
  44.         private int editorCount;
  45.        
  46.         /// <devdoc>
  47.         /// <para>
  48.         /// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with the specified name and
  49.         /// attributes.
  50.         /// </para>
  51.         /// </devdoc>
  52.         protected PropertyDescriptor(string name, Attribute[] attrs) : base(name, attrs)
  53.         {
  54.         }
  55.        
  56.         /// <devdoc>
  57.         /// <para>
  58.         /// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with
  59.         /// the name and attributes in the specified <see cref='System.ComponentModel.MemberDescriptor'/>.
  60.         /// </para>
  61.         /// </devdoc>
  62.         protected PropertyDescriptor(MemberDescriptor descr) : base(descr)
  63.         {
  64.         }
  65.        
  66.         /// <devdoc>
  67.         /// <para>
  68.         /// Initializes a new instance of the <see cref='System.ComponentModel.PropertyDescriptor'/> class with
  69.         /// the name in the specified <see cref='System.ComponentModel.MemberDescriptor'/> and the
  70.         /// attributes in both the <see cref='System.ComponentModel.MemberDescriptor'/> and the
  71.         /// <see cref='System.Attribute'/> array.
  72.         /// </para>
  73.         /// </devdoc>
  74.         protected PropertyDescriptor(MemberDescriptor descr, Attribute[] attrs) : base(descr, attrs)
  75.         {
  76.         }
  77.        
  78.         /// <devdoc>
  79.         /// <para>
  80.         /// When overridden in a derived class, gets the type of the
  81.         /// component this property
  82.         /// is bound to.
  83.         /// </para>
  84.         /// </devdoc>
  85.         public abstract Type ComponentType {
  86.             get;
  87.         }
  88.        
  89.         /// <devdoc>
  90.         /// <para>
  91.         /// Gets the type converter for this property.
  92.         /// </para>
  93.         /// </devdoc>
  94.         public virtual TypeConverter Converter {
  95.             get {
  96.                 // Always grab the attribute collection first here, because if the metadata version
  97.                 // changes it will invalidate our type converter cache.
  98.                 AttributeCollection attrs = Attributes;
  99.                
  100.                 if (converter == null) {
  101.                     TypeConverterAttribute attr = (TypeConverterAttribute)attrs[typeof(TypeConverterAttribute)];
  102.                     if (attr.ConverterTypeName != null && attr.ConverterTypeName.Length > 0) {
  103.                         Type converterType = GetTypeFromName(attr.ConverterTypeName);
  104.                         if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) {
  105.                             converter = (TypeConverter)CreateInstance(converterType);
  106.                         }
  107.                     }
  108.                    
  109.                     if (converter == null) {
  110.                         converter = TypeDescriptor.GetConverter(PropertyType);
  111.                     }
  112.                 }
  113.                 return converter;
  114.             }
  115.         }
  116.        
  117.         /// <devdoc>
  118.         /// <para>
  119.         /// Gets a value
  120.         /// indicating whether this property should be localized, as
  121.         /// specified in the <see cref='System.ComponentModel.LocalizableAttribute'/>.
  122.         /// </para>
  123.         /// </devdoc>
  124.         public virtual bool IsLocalizable {
  125.             get { return (LocalizableAttribute.Yes.Equals(Attributes[typeof(LocalizableAttribute)])); }
  126.         }
  127.        
  128.         /// <devdoc>
  129.         /// <para>
  130.         /// When overridden in
  131.         /// a derived class, gets a value
  132.         /// indicating whether this property is read-only.
  133.         /// </para>
  134.         /// </devdoc>
  135.         public abstract bool IsReadOnly {
  136.             get;
  137.         }
  138.        
  139.         /// <devdoc>
  140.         /// <para>
  141.         /// Gets a value
  142.         /// indicating whether this property should be serialized as specified in the <see cref='System.ComponentModel.DesignerSerializationVisibilityAttribute'/>.
  143.         /// </para>
  144.         /// </devdoc>
  145.         public DesignerSerializationVisibility SerializationVisibility {
  146.             get {
  147.                 DesignerSerializationVisibilityAttribute attr = (DesignerSerializationVisibilityAttribute)Attributes[typeof(DesignerSerializationVisibilityAttribute)];
  148.                 return attr.Visibility;
  149.             }
  150.         }
  151.        
  152.         /// <devdoc>
  153.         /// <para>
  154.         /// When overridden in a derived class,
  155.         /// gets the type of the property.
  156.         /// </para>
  157.         /// </devdoc>
  158.         public abstract Type PropertyType {
  159.             get;
  160.         }
  161.        
  162.         /// <devdoc>
  163.         /// Allows interested objects to be notified when this property changes.
  164.         /// </devdoc>
  165.         public virtual void AddValueChanged(object component, EventHandler handler)
  166.         {
  167.             if (component == null)
  168.                 throw new ArgumentNullException("component");
  169.             if (handler == null)
  170.                 throw new ArgumentNullException("handler");
  171.            
  172.             if (valueChangedHandlers == null) {
  173.                 valueChangedHandlers = new Hashtable();
  174.             }
  175.            
  176.             EventHandler h = (EventHandler)valueChangedHandlers[component];
  177.             valueChangedHandlers[component] = Delegate.Combine(h, handler);
  178.         }
  179.        
  180.         /// <devdoc>
  181.         /// <para>
  182.         /// When overridden in a derived class, indicates whether
  183.         /// resetting the <paramref name="component "/>will change the value of the
  184.         /// <paramref name="component"/>.
  185.         /// </para>
  186.         /// </devdoc>
  187.         public abstract bool CanResetValue(object component);
  188.        
  189.         /// <devdoc>
  190.         /// <para>
  191.         /// Compares this to another <see cref='System.ComponentModel.PropertyDescriptor'/>
  192.         /// to see if they are equivalent.
  193.         /// NOTE: If you make a change here, you likely need to change GetHashCode() as well.
  194.         /// </para>
  195.         /// </devdoc>
  196.         public override bool Equals(object obj)
  197.         {
  198.             try {
  199.                 if (obj == this) {
  200.                     return true;
  201.                 }
  202.                
  203.                 if (obj == null) {
  204.                     return false;
  205.                 }
  206.                
  207.                 // Assume that 90% of the time we will only do a .Equals(...) for
  208.                 // propertydescriptor vs. propertydescriptor... avoid the overhead
  209.                 // of an instanceof call.
  210.                 PropertyDescriptor pd = obj as PropertyDescriptor;
  211.                
  212.                 if (pd != null && pd.NameHashCode == this.NameHashCode && pd.PropertyType == this.PropertyType && pd.Name.Equals(this.Name)) {
  213.                    
  214.                     return true;
  215.                 }
  216.             }
  217.             catch {
  218.             }
  219.            
  220.             return false;
  221.         }
  222.        
  223.         /// <devdoc>
  224.         /// <para>
  225.         /// Creates an instance of the
  226.         /// specified type.
  227.         /// </para>
  228.         /// </devdoc>
  229.         protected object CreateInstance(Type type)
  230.         {
  231.             Type[] typeArgs = new Type[] {typeof(Type)};
  232.             ConstructorInfo ctor = type.GetConstructor(typeArgs);
  233.             if (ctor != null) {
  234.                 return TypeDescriptor.CreateInstance(null, type, typeArgs, new object[] {PropertyType});
  235.             }
  236.            
  237.             return TypeDescriptor.CreateInstance(null, type, null, null);
  238.         }
  239.        
  240.         /// <devdoc>
  241.         /// In an inheriting class, adds the attributes of the inheriting class to the
  242.         /// specified list of attributes in the parent class. For duplicate attributes,
  243.         /// the last one added to the list will be kept.
  244.         /// </devdoc>
  245.         protected override void FillAttributes(IList attributeList)
  246.         {
  247.            
  248.             // Each time we fill our attributes, we should clear our cached
  249.             // stuff.
  250.             converter = null;
  251.             editors = null;
  252.             editorTypes = null;
  253.             editorCount = 0;
  254.            
  255.             base.FillAttributes(attributeList);
  256.         }
  257.        
  258.         /// <include file='doc\PropertyDescriptor.uex' path='docs/doc[@for="PropertyDescriptor.GetChildProperties"]/*' />
  259.         /// <devdoc>
  260.         /// <para>[To be supplied.]</para>
  261.         /// </devdoc>
  262.         public PropertyDescriptorCollection GetChildProperties()
  263.         {
  264.             return GetChildProperties(null, null);
  265.         }
  266.        
  267.         /// <devdoc>
  268.         /// <para>[To be supplied.]</para>
  269.         /// </devdoc>
  270.         public PropertyDescriptorCollection GetChildProperties(Attribute[] filter)
  271.         {
  272.             return GetChildProperties(null, filter);
  273.         }
  274.        
  275.         /// <devdoc>
  276.         /// <para>[To be supplied.]</para>
  277.         /// </devdoc>
  278.         public PropertyDescriptorCollection GetChildProperties(object instance)
  279.         {
  280.             return GetChildProperties(instance, null);
  281.         }
  282.        
  283.         /// <devdoc>
  284.         /// Retrieves the properties
  285.         /// </devdoc>
  286.         public virtual PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
  287.         {
  288.             if (instance == null) {
  289.                 return TypeDescriptor.GetProperties(PropertyType, filter);
  290.             }
  291.             else {
  292.                 return TypeDescriptor.GetProperties(instance, filter);
  293.             }
  294.         }
  295.        
  296.        
  297.         /// <devdoc>
  298.         /// <para>
  299.         /// Gets an editor of the specified type.
  300.         /// </para>
  301.         /// </devdoc>
  302.         public virtual object GetEditor(Type editorBaseType)
  303.         {
  304.             object editor = null;
  305.            
  306.             // Always grab the attribute collection first here, because if the metadata version
  307.             // changes it will invalidate our editor cache.
  308.             AttributeCollection attrs = Attributes;
  309.            
  310.             // Check the editors we've already created for this type.
  311.             //
  312.             if (editorTypes != null) {
  313.                 for (int i = 0; i < editorCount; i++) {
  314.                     if (editorTypes[i] == editorBaseType) {
  315.                         return editors[i];
  316.                     }
  317.                 }
  318.             }
  319.            
  320.             // If one wasn't found, then we must go through the attributes.
  321.             //
  322.             if (editor == null) {
  323.                 for (int i = 0; i < attrs.Count; i++) {
  324.                     EditorAttribute attr = attrs[i] as EditorAttribute;
  325.                     if (attr == null) {
  326.                         continue;
  327.                     }
  328.                    
  329.                     Type editorType = GetTypeFromName(attr.EditorBaseTypeName);
  330.                    
  331.                     if (editorBaseType == editorType) {
  332.                         Type type = GetTypeFromName(attr.EditorTypeName);
  333.                         if (type != null) {
  334.                             editor = CreateInstance(type);
  335.                             break;
  336.                         }
  337.                     }
  338.                 }
  339.                
  340.                 // Now, if we failed to find it in our own attributes, go to the
  341.                 // component descriptor.
  342.                 //
  343.                 if (editor == null) {
  344.                     editor = TypeDescriptor.GetEditor(PropertyType, editorBaseType);
  345.                 }
  346.                
  347.                 // Now, another slot in our editor cache for next time
  348.                 //
  349.                 if (editorTypes == null) {
  350.                     editorTypes = new Type[5];
  351.                     editors = new object[5];
  352.                 }
  353.                
  354.                 if (editorCount >= editorTypes.Length) {
  355.                     Type[] newTypes = new Type[editorTypes.Length * 2];
  356.                     object[] newEditors = new object[editors.Length * 2];
  357.                     Array.Copy(editorTypes, newTypes, editorTypes.Length);
  358.                     Array.Copy(editors, newEditors, editors.Length);
  359.                     editorTypes = newTypes;
  360.                     editors = newEditors;
  361.                 }
  362.                
  363.                 editorTypes[editorCount] = editorBaseType;
  364.                 editors[editorCount++] = editor;
  365.             }
  366.            
  367.             return editor;
  368.         }
  369.        
  370.         /// <devdoc>
  371.         /// Try to keep this reasonable in sync with Equals(). Specifically,
  372.         /// if A.Equals(B) returns true, A & B should have the same hash code.
  373.         /// </devdoc>
  374.         public override int GetHashCode()
  375.         {
  376.             return this.NameHashCode ^ PropertyType.GetHashCode();
  377.         }
  378.        
  379.         /// <devdoc>
  380.         /// This method returns the object that should be used during invocation of members.
  381.         /// Normally the return value will be the same as the instance passed in. If
  382.         /// someone associated another object with this instance, or if the instance is a
  383.         /// custom type descriptor, GetInvocationTarget may return a different value.
  384.         /// </devdoc>
  385.         protected override object GetInvocationTarget(Type type, object instance)
  386.         {
  387.             object target = base.GetInvocationTarget(type, instance);
  388.             ICustomTypeDescriptor td = target as ICustomTypeDescriptor;
  389.             if (td != null) {
  390.                 target = td.GetPropertyOwner(this);
  391.             }
  392.            
  393.             return target;
  394.         }
  395.        
  396.        
  397.         /// <devdoc>
  398.         /// <para>Gets a type using its name.</para>
  399.         /// </devdoc>
  400.         protected Type GetTypeFromName(string typeName)
  401.         {
  402.            
  403.             if (typeName == null || typeName.Length == 0) {
  404.                 return null;
  405.             }
  406.            
  407.             // try the generic method.
  408.             //
  409.             Type t = Type.GetType(typeName);
  410.            
  411.             // try the assembly of the component
  412.             //
  413.             if (t == null && ComponentType != null) {
  414.                 int comma = typeName.IndexOf(',');
  415.                
  416.                 if (comma != -1) {
  417.                     typeName = typeName.Substring(0, comma);
  418.                 }
  419.                 t = ComponentType.Assembly.GetType(typeName);
  420.             }
  421.            
  422.             return t;
  423.         }
  424.        
  425.         /// <devdoc>
  426.         /// <para>
  427.         /// When overridden in a derived class, gets the current
  428.         /// value
  429.         /// of the
  430.         /// property on a component.
  431.         /// </para>
  432.         /// </devdoc>
  433.         public abstract object GetValue(object component);
  434.        
  435.         /// <devdoc>
  436.         /// This should be called by your property descriptor implementation
  437.         /// when the property value has changed.
  438.         /// </devdoc>
  439.         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
  440.         protected virtual void OnValueChanged(object component, EventArgs e)
  441.         {
  442.             if (component != null && valueChangedHandlers != null) {
  443.                 EventHandler handler = (EventHandler)valueChangedHandlers[component];
  444.                 if (handler != null) {
  445.                     handler(component, e);
  446.                 }
  447.             }
  448.         }
  449.        
  450.         /// <devdoc>
  451.         /// Allows interested objects to be notified when this property changes.
  452.         /// </devdoc>
  453.         public virtual void RemoveValueChanged(object component, EventHandler handler)
  454.         {
  455.             if (component == null)
  456.                 throw new ArgumentNullException("component");
  457.             if (handler == null)
  458.                 throw new ArgumentNullException("handler");
  459.            
  460.             if (valueChangedHandlers != null) {
  461.                 EventHandler h = (EventHandler)valueChangedHandlers[component];
  462.                 h = (EventHandler)Delegate.Remove(h, handler);
  463.                 if (h != null) {
  464.                     valueChangedHandlers[component] = h;
  465.                 }
  466.                 else {
  467.                     valueChangedHandlers.Remove(component);
  468.                 }
  469.             }
  470.         }
  471.        
  472.         /// <devdoc>
  473.         /// Return current set of ValueChanged event handlers for a specific
  474.         /// component, in the form of a combined multicast event handler.
  475.         /// Returns null if no event handlers currently assigned to component.
  476.         /// </devdoc>
  477.         protected internal EventHandler GetValueChangedHandler(object component)
  478.         {
  479.             if (component != null && valueChangedHandlers != null) {
  480.                 return (EventHandler)valueChangedHandlers[component];
  481.             }
  482.             else {
  483.                 return null;
  484.             }
  485.         }
  486.        
  487.         /// <devdoc>
  488.         /// <para>
  489.         /// When overridden in a derived class, resets the
  490.         /// value
  491.         /// for this property
  492.         /// of the component.
  493.         /// </para>
  494.         /// </devdoc>
  495.         public abstract void ResetValue(object component);
  496.        
  497.         /// <devdoc>
  498.         /// <para>
  499.         /// When overridden in a derived class, sets the value of
  500.         /// the component to a different value.
  501.         /// </para>
  502.         /// </devdoc>
  503.         public abstract void SetValue(object component, object value);
  504.        
  505.         /// <devdoc>
  506.         /// <para>
  507.         /// When overridden in a derived class, indicates whether the
  508.         /// value of
  509.         /// this property needs to be persisted.
  510.         /// </para>
  511.         /// </devdoc>
  512.         public abstract bool ShouldSerializeValue(object component);
  513.        
  514.         /// <devdoc>
  515.         /// Indicates whether value change notifications for this property may originate from outside the property
  516.         /// descriptor, such as from the component itself (value=true), or whether notifications will only originate
  517.         /// from direct calls made to PropertyDescriptor.SetValue (value=false). For example, the component may
  518.         /// implement the INotifyPropertyChanged interface, or may have an explicit '{name}Changed' event for this property.
  519.         /// </devdoc>
  520.         public virtual bool SupportsChangeEvents {
  521.             get { return false; }
  522.         }
  523.        
  524.     }
  525. }

Developer Fusion