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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="DebugReflectPropertyDescriptor.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. #if DEBUG
  16. /*
  17.    
  18.     This class exists in debug only.  It is a complete copy of the
  19.     V1.0 TypeDescriptor object and is used to validate that the
  20.     behavior of the V2.0 TypeDescriptor matches 1.0 behavior.
  21.    
  22. */
  23. namespace System.ComponentModel
  24. {
  25.     using System.Runtime.Serialization.Formatters;
  26.     using System.Runtime.InteropServices;
  27.     using System.Diagnostics;
  28.     using System;
  29.     using System.Collections;
  30.     using System.Collections.Specialized;
  31.     using System.Reflection;
  32.     using Microsoft.Win32;
  33.     using System.Security;
  34.     using System.Security.Permissions;
  35.     using System.ComponentModel.Design;
  36.     using System.ComponentModel;
  37.    
  38.     /// <internalonly/>
  39.     /// <devdoc>
  40.     /// <para>
  41.     /// DebugReflectPropertyDescriptor defines a property. Properties are the main way that a user can
  42.     /// set up the state of a component.
  43.     /// The DebugReflectPropertyDescriptor class takes a component class that the property lives on,
  44.     /// a property name, the type of the property, and various attributes for the
  45.     /// property.
  46.     /// For a property named XXX of type YYY, the associated component class is
  47.     /// required to implement two methods of the following
  48.     /// form:
  49.     /// </para>
  50.     /// <code>
  51.     /// public YYY GetXXX();
  52.     /// public void SetXXX(YYY value);
  53.     /// </code>
  54.     /// The component class can optionally implement two additional methods of
  55.     /// the following form:
  56.     /// <code>
  57.     /// public boolean ShouldSerializeXXX();
  58.     /// public void ResetXXX();
  59.     /// </code>
  60.     /// These methods deal with a property's default value. The ShouldSerializeXXX()
  61.     /// method returns true if the current value of the XXX property is different
  62.     /// than it's default value, so that it should be persisted out. The ResetXXX()
  63.     /// method resets the XXX property to its default value. If the DebugReflectPropertyDescriptor
  64.     /// includes the default value of the property (using the DefaultValueAttribute),
  65.     /// the ShouldSerializeXXX() and ResetXXX() methods are ignored.
  66.     /// If the DebugReflectPropertyDescriptor includes a reference to an editor
  67.     /// then that value editor will be used to
  68.     /// edit the property. Otherwise, a system-provided editor will be used.
  69.     /// Various attributes can be passed to the DebugReflectPropertyDescriptor, as are described in
  70.     /// Attribute.
  71.     /// ReflectPropertyDescriptors can be obtained by a user programmatically through the
  72.     /// ComponentManager.
  73.     /// </devdoc>
  74.     [HostProtection(SharedState = true)]
  75.     internal sealed class DebugReflectPropertyDescriptor : PropertyDescriptor
  76.     {
  77.        
  78.         private static readonly Type[] argsNone = new Type[0];
  79.         private static readonly object noValue = new object();
  80.        
  81.         private static TraceSwitch PropDescCreateSwitch = new TraceSwitch("PropDescCreate", "DebugReflectPropertyDescriptor: Dump errors when creating property info");
  82.         private static TraceSwitch PropDescUsageSwitch = new TraceSwitch("PropDescUsage", "DebugReflectPropertyDescriptor: Debug propertydescriptor usage");
  83.         private static TraceSwitch PropDescSwitch = new TraceSwitch("PropDesc", "DebugReflectPropertyDescriptor: Debug property descriptor");
  84.        
  85.         private static readonly int BitDefaultValueQueried = BitVector32.CreateMask();
  86.         private static readonly int BitGetQueried = BitVector32.CreateMask(BitDefaultValueQueried);
  87.         private static readonly int BitSetQueried = BitVector32.CreateMask(BitGetQueried);
  88.         private static readonly int BitShouldSerializeQueried = BitVector32.CreateMask(BitSetQueried);
  89.         private static readonly int BitResetQueried = BitVector32.CreateMask(BitShouldSerializeQueried);
  90.         private static readonly int BitChangedQueried = BitVector32.CreateMask(BitResetQueried);
  91.         private static readonly int BitReadOnlyChecked = BitVector32.CreateMask(BitChangedQueried);
  92.         private static readonly int BitAmbientValueQueried = BitVector32.CreateMask(BitReadOnlyChecked);
  93.        
  94.         internal BitVector32 state = new BitVector32();
  95.         // Contains the state bits for this proeprty descriptor.
  96.         Type componentClass;
  97.         // used to determine if we should all on us or on the designer
  98.         Type type;
  99.         // the data type of the property
  100.         internal object defaultValue;
  101.         // the default value of the property (or noValue)
  102.         internal object ambientValue;
  103.         // the ambient value of the property (or noValue)
  104.         internal PropertyInfo propInfo;
  105.         // the property info
  106.         internal MethodInfo getMethod;
  107.         // the property get method
  108.         internal MethodInfo setMethod;
  109.         // the property set method
  110.         internal MethodInfo shouldSerializeMethod;
  111.         // the should serialize method
  112.         internal MethodInfo resetMethod;
  113.         // the reset property method
  114.         EventInfo realChangedEventInfo;
  115.         // Changed event handler on object
  116.         Type receiverType;
  117.         // Only set if we are an extender
  118.         private TypeConverter converter;
  119.         private object[] editors;
  120.         private Type[] editorTypes;
  121.         private int editorCount;
  122.        
  123.         /// <devdoc>
  124.         /// The main constructor for ReflectPropertyDescriptors.
  125.         /// </devdoc>
  126.         public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type, Attribute[] attributes) : base(name, attributes)
  127.         {
  128.            
  129.             Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "Creating DebugReflectPropertyDescriptor for " + componentClass.FullName + "." + name);
  130.            
  131.             try {
  132.                 if (type == null) {
  133.                     Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "type == null, name == " + name);
  134.                     throw new ArgumentException(SR.GetString(SR.ErrorInvalidPropertyType, name));
  135.                 }
  136.                 if (componentClass == null) {
  137.                     Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "componentClass == null, name == " + name);
  138.                     throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
  139.                 }
  140.                 this.type = type;
  141.                 this.componentClass = componentClass;
  142.             }
  143.             catch (Exception t) {
  144.                 Debug.Fail("Property '" + name + "' on component " + componentClass.FullName + " failed to init.");
  145.                 Debug.Fail(t.ToString());
  146.                 throw t;
  147.             }
  148.             catch {
  149.                 throw;
  150.             }
  151.         }
  152.        
  153.         /// <devdoc>
  154.         /// A constructor for ReflectPropertyDescriptors that have no attributes.
  155.         /// </devdoc>
  156.         public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type, PropertyInfo propInfo, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs)
  157.         {
  158.             this.propInfo = propInfo;
  159.             this.getMethod = getMethod;
  160.             this.setMethod = setMethod;
  161.             state[BitGetQueried | BitSetQueried] = true;
  162.         }
  163.        
  164.         /// <devdoc>
  165.         /// A constructor for ReflectPropertyDescriptors that creates an extender property.
  166.         /// </devdoc>
  167.         public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type, Type receiverType, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs)
  168.         {
  169.             this.receiverType = receiverType;
  170.             this.getMethod = getMethod;
  171.             this.setMethod = setMethod;
  172.             state[BitGetQueried | BitSetQueried] = true;
  173.         }
  174.        
  175.         /// <devdoc>
  176.         /// This constructor takes an existing DebugReflectPropertyDescriptor and modifies it by merging in the
  177.         /// passed-in attributes.
  178.         /// </devdoc>
  179.         public DebugReflectPropertyDescriptor(Type componentClass, PropertyDescriptor oldReflectPropertyDescriptor, Attribute[] attributes) : base(oldReflectPropertyDescriptor, attributes)
  180.         {
  181.            
  182.             this.componentClass = componentClass;
  183.             this.type = oldReflectPropertyDescriptor.PropertyType;
  184.            
  185.             if (componentClass == null) {
  186.                 throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
  187.             }
  188.            
  189.             // If the classes are the same, we can potentially optimize the method fetch because
  190.             // the old property descriptor may already have it.
  191.             //
  192.             if (oldReflectPropertyDescriptor is DebugReflectPropertyDescriptor) {
  193.                 DebugReflectPropertyDescriptor oldProp = (DebugReflectPropertyDescriptor)oldReflectPropertyDescriptor;
  194.                
  195.                 if (oldProp.ComponentType == componentClass) {
  196.                     propInfo = oldProp.propInfo;
  197.                     getMethod = oldProp.getMethod;
  198.                     setMethod = oldProp.setMethod;
  199.                     shouldSerializeMethod = oldProp.shouldSerializeMethod;
  200.                     resetMethod = oldProp.resetMethod;
  201.                     defaultValue = oldProp.defaultValue;
  202.                     ambientValue = oldProp.ambientValue;
  203.                     state = oldProp.state;
  204.                 }
  205.                
  206.                 // Now we must figure out what to do with our default value. First, check to see
  207.                 // if the caller has provided an new default value attribute. If so, use it. Otherwise,
  208.                 // just let it be and it will be picked up on demand.
  209.                 //
  210.                 if (attributes != null) {
  211.                     foreach (Attribute a in attributes) {
  212.                         if (a is DefaultValueAttribute) {
  213.                             defaultValue = ((DefaultValueAttribute)a).Value;
  214.                             state[BitDefaultValueQueried] = true;
  215.                         }
  216.                         else if (a is AmbientValueAttribute) {
  217.                             ambientValue = ((AmbientValueAttribute)a).Value;
  218.                             state[BitAmbientValueQueried] = true;
  219.                         }
  220.                     }
  221.                 }
  222.             }
  223.         }
  224.        
  225.         /// <devdoc>
  226.         /// Retrieves the ambient value for this property.
  227.         /// </devdoc>
  228.         private object AmbientValue {
  229.             get {
  230.                 if (!state[BitAmbientValueQueried]) {
  231.                     state[BitAmbientValueQueried] = true;
  232.                     Attribute a = Attributes[typeof(AmbientValueAttribute)];
  233.                     if (a != null) {
  234.                         ambientValue = ((AmbientValueAttribute)a).Value;
  235.                     }
  236.                     else {
  237.                         ambientValue = noValue;
  238.                     }
  239.                 }
  240.                 return ambientValue;
  241.             }
  242.         }
  243.        
  244.         /// <devdoc>
  245.         /// The EventInfo for the changed event on the component, or null if there isn't one for this property.
  246.         /// </devdoc>
  247.         private EventInfo ChangedEventValue {
  248.             get {
  249.                 if (!state[BitChangedQueried]) {
  250.                     state[BitChangedQueried] = true;
  251.                     realChangedEventInfo = ComponentType.GetEvent(Name + "Changed", BindingFlags.Public | BindingFlags.Instance);
  252.                 }
  253.                 return realChangedEventInfo;
  254.             }
  255.         }
  256.        
  257. /*
  258.             The following code has been removed to fix FXCOP violations.  The code
  259.             is left here incase it needs to be resurrected in the future.
  260.             set {
  261.                 realChangedEventInfo = value;
  262.                 state[BitChangedQueried] = true;
  263.             }
  264.             */       
  265.        
  266.         /// <devdoc>
  267.         /// Retrieves the type of the component this PropertyDescriptor is bound to.
  268.         /// </devdoc>
  269.         public override Type ComponentType {
  270.             get { return componentClass; }
  271.         }
  272.        
  273.         /// <devdoc>
  274.         /// <para>
  275.         /// Gets the type converter for this property.
  276.         /// </para>
  277.         /// </devdoc>
  278.         public override TypeConverter Converter {
  279.             get {
  280.                 if (converter == null) {
  281.                     TypeConverterAttribute attr = (TypeConverterAttribute)Attributes[typeof(TypeConverterAttribute)];
  282.                     if (attr.ConverterTypeName != null && attr.ConverterTypeName.Length > 0) {
  283.                         Type converterType = GetTypeFromName(attr.ConverterTypeName);
  284.                         if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) {
  285.                             converter = (TypeConverter)CreateInstance(converterType);
  286.                         }
  287.                     }
  288.                    
  289.                     if (converter == null) {
  290.                         converter = DebugTypeDescriptor.GetConverter(PropertyType);
  291.                     }
  292.                 }
  293.                 return converter;
  294.             }
  295.         }
  296.        
  297.         /// <devdoc>
  298.         /// Retrieves the default value for this property.
  299.         /// </devdoc>
  300.         private object DefaultValue {
  301.             get {
  302.                 if (!state[BitDefaultValueQueried]) {
  303.                     state[BitDefaultValueQueried] = true;
  304.                     Attribute a = Attributes[typeof(DefaultValueAttribute)];
  305.                     if (a != null) {
  306.                         defaultValue = ((DefaultValueAttribute)a).Value;
  307.                     }
  308.                     else {
  309.                         defaultValue = noValue;
  310.                     }
  311.                 }
  312.                 return defaultValue;
  313.             }
  314.         }
  315.        
  316.         /// <devdoc>
  317.         /// The GetMethod for this property
  318.         /// </devdoc>
  319.         private MethodInfo GetMethodValue {
  320.             get {
  321.                 if (!state[BitGetQueried]) {
  322.                     state[BitGetQueried] = true;
  323.                    
  324.                     if (receiverType == null) {
  325.                         if (propInfo == null) {
  326.                             BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
  327.                             propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
  328.                         }
  329.                         if (propInfo != null) {
  330.                             getMethod = propInfo.GetGetMethod(true);
  331.                         }
  332.                         if (getMethod == null) {
  333.                             throw new InvalidOperationException(SR.GetString(SR.ErrorMissingPropertyAccessors, componentClass.FullName + "." + Name));
  334.                         }
  335.                     }
  336.                     else {
  337.                         getMethod = FindMethod(componentClass, "Get" + Name, new Type[] {receiverType}, type);
  338.                         if (getMethod == null) {
  339.                             throw new ArgumentException(SR.GetString(SR.ErrorMissingPropertyAccessors, Name));
  340.                         }
  341.                     }
  342.                 }
  343.                 return getMethod;
  344.             }
  345.         }
  346.        
  347. /*
  348.             The following code has been removed to fix FXCOP violations.  The code
  349.             is left here incase it needs to be resurrected in the future.
  350.             set {
  351.                 state[BitGetQueried] = true;
  352.                 getMethod = value;
  353.             }
  354.             */       
  355.        
  356.         /// <devdoc>
  357.         /// Determines if this property is an extender property.
  358.         /// </devdoc>
  359.         private bool IsExtender {
  360.             get { return (receiverType != null); }
  361.         }
  362.        
  363.         /// <devdoc>
  364.         /// Indicates whether this property is read only.
  365.         /// </devdoc>
  366.         public override bool IsReadOnly {
  367.             get { return SetMethodValue == null || ((ReadOnlyAttribute)Attributes[typeof(ReadOnlyAttribute)]).IsReadOnly; }
  368.         }
  369.        
  370.         /// <devdoc>
  371.         /// Retrieves the type of the property.
  372.         /// </devdoc>
  373.         public override Type PropertyType {
  374.             get { return type; }
  375.         }
  376.        
  377.         /// <devdoc>
  378.         /// Access to the reset method, if one exists for this property.
  379.         /// </devdoc>
  380.         private MethodInfo ResetMethodValue {
  381.             get {
  382.                 if (!state[BitResetQueried]) {
  383.                     state[BitResetQueried] = true;
  384.                    
  385.                     Type[] args;
  386.                    
  387.                     if (receiverType == null) {
  388.                         args = argsNone;
  389.                     }
  390.                     else {
  391.                         args = new Type[] {receiverType};
  392.                     }
  393.                    
  394.                     IntSecurity.FullReflection.Assert();
  395.                     try {
  396.                             /* publicOnly= */                        resetMethod = FindMethod(componentClass, "Reset" + Name, args, typeof(void), false);
  397.                     }
  398.                     finally {
  399.                         CodeAccessPermission.RevertAssert();
  400.                     }
  401.                 }
  402.                 return resetMethod;
  403.             }
  404.         }
  405.        
  406. /*
  407.             The following code has been removed to fix FXCOP violations.  The code
  408.             is left here incase it needs to be resurrected in the future.
  409.             set {
  410.                 state[BitResetQueried] = true;
  411.                 resetMethod = value;
  412.             }
  413.             */       
  414.        
  415.         /// <devdoc>
  416.         /// Accessor for the set method
  417.         /// </devdoc>
  418.         private MethodInfo SetMethodValue {
  419.             get {
  420.                 if (!state[BitSetQueried]) {
  421.                     state[BitSetQueried] = true;
  422.                    
  423.                     if (receiverType == null) {
  424.                         if (propInfo == null) {
  425.                             BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
  426.                             propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
  427.                         }
  428.                         if (propInfo != null) {
  429.                             setMethod = propInfo.GetSetMethod(true);
  430.                         }
  431.                     }
  432.                     else {
  433.                         setMethod = FindMethod(componentClass, "Set" + Name, new Type[] {receiverType, type}, typeof(void));
  434.                     }
  435.                 }
  436.                 return setMethod;
  437.             }
  438.         }
  439.        
  440. /*
  441.             The following code has been removed to fix FXCOP violations.  The code
  442.             is left here incase it needs to be resurrected in the future.
  443.             set {
  444.                 state[BitSetQueried] = true;
  445.                 setMethod = value;
  446.             }
  447.             */       
  448.        
  449.         /// <devdoc>
  450.         /// Accessor for the ShouldSerialize method.
  451.         /// </devdoc>
  452.         private MethodInfo ShouldSerializeMethodValue {
  453.             get {
  454.                 if (!state[BitShouldSerializeQueried]) {
  455.                     state[BitShouldSerializeQueried] = true;
  456.                    
  457.                     Type[] args;
  458.                    
  459.                     if (receiverType == null) {
  460.                         args = argsNone;
  461.                     }
  462.                     else {
  463.                         args = new Type[] {receiverType};
  464.                     }
  465.                    
  466.                     IntSecurity.FullReflection.Assert();
  467.                     try {
  468.                             /* publicOnly= */                        shouldSerializeMethod = FindMethod(componentClass, "ShouldSerialize" + Name, args, typeof(bool), false);
  469.                     }
  470.                     finally {
  471.                         CodeAccessPermission.RevertAssert();
  472.                     }
  473.                 }
  474.                 return shouldSerializeMethod;
  475.             }
  476.         }
  477.        
  478. /*
  479.             The following code has been removed to fix FXCOP violations.  The code
  480.             is left here incase it needs to be resurrected in the future.
  481.             set {
  482.                 state[BitShouldSerializeQueried] = true;
  483.                 shouldSerializeMethod = value;
  484.             }
  485.             */       
  486.        
  487.         /// <devdoc>
  488.         /// Allows interested objects to be notified when this property changes.
  489.         /// </devdoc>
  490.         public override void AddValueChanged(object component, EventHandler handler)
  491.         {
  492.             if (component == null)
  493.                 throw new ArgumentNullException("component");
  494.             if (handler == null)
  495.                 throw new ArgumentNullException("handler");
  496.            
  497.             EventInfo changedEvent = ChangedEventValue;
  498.             if (changedEvent != null) {
  499.                 changedEvent.AddEventHandler(component, handler);
  500.             }
  501.             else {
  502.                 base.AddValueChanged(component, handler);
  503.             }
  504.         }
  505.        
  506.         internal bool ExtenderCanResetValue(IExtenderProvider provider, object component)
  507.         {
  508.             if (DefaultValue != noValue) {
  509.                 return !object.Equals(ExtenderGetValue(provider, component), defaultValue);
  510.             }
  511.            
  512.             MethodInfo reset = ResetMethodValue;
  513.             if (reset != null) {
  514.                 MethodInfo shouldSerialize = ShouldSerializeMethodValue;
  515.                 if (shouldSerialize != null) {
  516.                     try {
  517.                         provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
  518.                         return (bool)shouldSerialize.Invoke(provider, new object[] {component});
  519.                     }
  520.                     catch {
  521.                     }
  522.                 }
  523.             }
  524.             else {
  525.                 return true;
  526.             }
  527.             return false;
  528.         }
  529.        
  530.         internal Type ExtenderGetReceiverType()
  531.         {
  532.             return receiverType;
  533.         }
  534.        
  535.         internal Type ExtenderGetType(IExtenderProvider provider)
  536.         {
  537.             return PropertyType;
  538.         }
  539.        
  540.         internal object ExtenderGetValue(IExtenderProvider provider, object component)
  541.         {
  542.             if (provider != null) {
  543.                 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
  544.                 return GetMethodValue.Invoke(provider, new object[] {component});
  545.             }
  546.             return null;
  547.         }
  548.        
  549.         internal void ExtenderResetValue(IExtenderProvider provider, object component, PropertyDescriptor notifyDesc)
  550.         {
  551.             if (DefaultValue != noValue) {
  552.                 ExtenderSetValue(provider, component, DefaultValue, notifyDesc);
  553.             }
  554.             else if (AmbientValue != noValue) {
  555.                 ExtenderSetValue(provider, component, AmbientValue, notifyDesc);
  556.             }
  557.             else if (ResetMethodValue != null) {
  558.                 ISite site = GetSite(component);
  559.                 IComponentChangeService changeService = null;
  560.                 object oldValue = null;
  561.                 object newValue;
  562.                
  563.                 // Announce that we are about to change this component
  564.                 //
  565.                 if (site != null) {
  566.                     changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
  567.                     Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
  568.                 }
  569.                
  570.                 // Make sure that it is ok to send the onchange events
  571.                 //
  572.                 if (changeService != null) {
  573.                     oldValue = ExtenderGetValue(provider, component);
  574.                     try {
  575.                         changeService.OnComponentChanging(component, notifyDesc);
  576.                     }
  577.                     catch (CheckoutException coEx) {
  578.                         if (coEx == CheckoutException.Canceled) {
  579.                             return;
  580.                         }
  581.                         throw coEx;
  582.                     }
  583.                 }
  584.                
  585.                 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
  586.                 if (ResetMethodValue != null) {
  587.                     ResetMethodValue.Invoke(provider, new object[] {component});
  588.                    
  589.                     // Now notify the change service that the change was successful.
  590.                     //
  591.                     if (changeService != null) {
  592.                         newValue = ExtenderGetValue(provider, component);
  593.                         changeService.OnComponentChanged(component, notifyDesc, oldValue, newValue);
  594.                     }
  595.                 }
  596.             }
  597.         }
  598.        
  599.         internal void ExtenderSetValue(IExtenderProvider provider, object component, object value, PropertyDescriptor notifyDesc)
  600.         {
  601.             if (provider != null) {
  602.                
  603.                 ISite site = GetSite(component);
  604.                 IComponentChangeService changeService = null;
  605.                 object oldValue = null;
  606.                
  607.                 // Announce that we are about to change this component
  608.                 //
  609.                 if (site != null) {
  610.                     changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
  611.                     Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
  612.                 }
  613.                
  614.                 // Make sure that it is ok to send the onchange events
  615.                 //
  616.                 if (changeService != null) {
  617.                     oldValue = ExtenderGetValue(provider, component);
  618.                     try {
  619.                         changeService.OnComponentChanging(component, notifyDesc);
  620.                     }
  621.                     catch (CheckoutException coEx) {
  622.                         if (coEx == CheckoutException.Canceled) {
  623.                             return;
  624.                         }
  625.                         throw coEx;
  626.                     }
  627.                 }
  628.                
  629.                 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
  630.                
  631.                 if (SetMethodValue != null) {
  632.                     SetMethodValue.Invoke(provider, new object[] {component, value});
  633.                    
  634.                     // Now notify the change service that the change was successful.
  635.                     //
  636.                     if (changeService != null) {
  637.                         changeService.OnComponentChanged(component, notifyDesc, oldValue, value);
  638.                     }
  639.                 }
  640.             }
  641.         }
  642.        
  643.         internal bool ExtenderShouldSerializeValue(IExtenderProvider provider, object component)
  644.         {
  645.            
  646.            
  647.             provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
  648.            
  649.             if (IsReadOnly) {
  650.                 if (ShouldSerializeMethodValue != null) {
  651.                     try {
  652.                         return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
  653.                     }
  654.                     catch {
  655.                     }
  656.                 }
  657.                 return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
  658.             }
  659.             else if (DefaultValue == noValue) {
  660.                 if (ShouldSerializeMethodValue != null) {
  661.                     try {
  662.                         return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
  663.                     }
  664.                     catch {
  665.                     }
  666.                 }
  667.                 return true;
  668.             }
  669.             return !object.Equals(DefaultValue, ExtenderGetValue(provider, component));
  670.         }
  671.        
  672.         /// <devdoc>
  673.         /// Indicates whether reset will change the value of the component. If there
  674.         /// is a DefaultValueAttribute, then this will return true if getValue returns
  675.         /// something different than the default value. If there is a reset method and
  676.         /// a ShouldSerialize method, this will return what ShouldSerialize returns.
  677.         /// If there is just a reset method, this always returns true. If none of these
  678.         /// cases apply, this returns false.
  679.         /// </devdoc>
  680.         public override bool CanResetValue(object component)
  681.         {
  682.             if (IsExtender) {
  683.                 return false;
  684.             }
  685.            
  686.             if (DefaultValue != noValue) {
  687.                 return !object.Equals(GetValue(component), DefaultValue);
  688.             }
  689.            
  690.             if (ResetMethodValue != null) {
  691.                 if (ShouldSerializeMethodValue != null) {
  692.                     component = GetDebugInvokee(componentClass, component);
  693.                     try {
  694.                         return (bool)ShouldSerializeMethodValue.Invoke(component, null);
  695.                     }
  696.                     catch {
  697.                     }
  698.                 }
  699.                 return true;
  700.             }
  701.            
  702.             if (AmbientValue != noValue) {
  703.                 return ShouldSerializeValue(component);
  704.             }
  705.            
  706.             return false;
  707.         }
  708.        
  709.         protected override void FillAttributes(IList attributes)
  710.         {
  711.             Debug.Assert(componentClass != null, "Must have a component class for FillAttributes");
  712.            
  713.             //
  714.             // The order that we fill in attributes is critical. The list of attributes will be
  715.             // filtered so that matching attributes at the end of the list replace earlier matches
  716.             // (last one in wins). Therefore, the three categories of attributes we add must be
  717.             // added as follows:
  718.             //
  719.             // 1. Attributes of the property type. These are the lowest level and should be
  720.             // overwritten by any newer attributes.
  721.             //
  722.             // 2. Attributes of the property itself, from base class to most derived. This way
  723.             // derived class attributes replace base class attributes.
  724.             //
  725.             // 3. Attributes from our base MemberDescriptor. While this seems opposite of what
  726.             // we want, MemberDescriptor only has attributes if someone passed in a new
  727.             // set in the constructor. Therefore, these attributes always
  728.             // supercede existing values.
  729.             //
  730.            
  731.            
  732.             // We need to include attributes from the type of the property.
  733.             //
  734.             foreach (Attribute typeAttr in DebugTypeDescriptor.GetAttributes(PropertyType)) {
  735.                 attributes.Add(typeAttr);
  736.             }
  737.            
  738.             // NOTE : Must look at method OR property, to handle the case of Extender properties...
  739.             //
  740.             // Note : Because we are using BindingFlags.DeclaredOnly it is more effcient to re-aquire
  741.             // : the property info, rather than use the one we have cached. The one we have cached
  742.             // : may ave come from a base class, meaning we will request custom metadata for this
  743.             // : class twice.
  744.            
  745.             BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;
  746.             Type currentReflectType = componentClass;
  747.             int depth = 0;
  748.            
  749.             // First, calculate the depth of the object hierarchy. We do this so we can do a single
  750.             // object create for an array of attributes.
  751.             //
  752.             while (currentReflectType != null && currentReflectType != typeof(object)) {
  753.                 depth++;
  754.                 currentReflectType = currentReflectType.BaseType;
  755.             }
  756.            
  757.             // Now build up an array in reverse order
  758.             //
  759.             if (depth > 0) {
  760.                 currentReflectType = componentClass;
  761.                 object[][] attributeStack = new object[depth][];
  762.                
  763.                 while (currentReflectType != null && currentReflectType != typeof(object)) {
  764.                    
  765.                     MemberInfo memberInfo = null;
  766.                    
  767.                     // Fill in our member info so we can get at the custom attributes.
  768.                     //
  769.                     if (IsExtender) {
  770.                         memberInfo = currentReflectType.GetMethod("Get" + Name, bindingFlags);
  771.                     }
  772.                     else {
  773.                         memberInfo = currentReflectType.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
  774.                     }
  775.                    
  776.                     // Get custom attributes for the member info.
  777.                     //
  778.                     if (memberInfo != null) {
  779.                         attributeStack[--depth] = DebugTypeDescriptor.GetCustomAttributes(memberInfo);
  780.                     }
  781.                    
  782.                     // Ready for the next loop iteration.
  783.                     //
  784.                     currentReflectType = currentReflectType.BaseType;
  785.                 }
  786.                
  787.                 // Now trawl the attribute stack so that we add attributes
  788.                 // from base class to most derived.
  789.                 //
  790.                 foreach (object[] attributeArray in attributeStack) {
  791.                     if (attributeArray != null) {
  792.                         foreach (object attr in attributeArray) {
  793.                             if (attr is Attribute) {
  794.                                 attributes.Add(attr);
  795.                             }
  796.                         }
  797.                     }
  798.                 }
  799.             }
  800.            
  801.             // Include the base attributes. These override all attributes on the actual
  802.             // property, so we want to add them last.
  803.             //
  804.             base.FillAttributes(attributes);
  805.            
  806.             // Finally, override any form of ReadOnlyAttribute.
  807.             //
  808.             if (!state[BitReadOnlyChecked]) {
  809.                 state[BitReadOnlyChecked] = true;
  810.                 if (SetMethodValue == null) {
  811.                     attributes.Add(ReadOnlyAttribute.Yes);
  812.                 }
  813.             }
  814.         }
  815.        
  816.         /// <devdoc>
  817.         /// Retrieves the properties
  818.         /// </devdoc>
  819.         public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
  820.         {
  821.             if (instance == null) {
  822.                 return DebugTypeDescriptor.GetProperties(PropertyType, filter);
  823.             }
  824.             else {
  825.                 return DebugTypeDescriptor.GetProperties(instance, filter);
  826.             }
  827.         }
  828.        
  829.         /// <devdoc>
  830.         /// <para>
  831.         /// Gets
  832.         /// the component
  833.         /// that a method should be invoked on.
  834.         /// </para>
  835.         /// </devdoc>
  836.         private static object GetDebugInvokee(Type componentClass, object component)
  837.         {
  838.            
  839.             // We delve into the component's designer only if it is a component and if
  840.             // the component we've been handed is not an instance of this property type.
  841.             //
  842.             if (!componentClass.IsInstanceOfType(component) && component is IComponent) {
  843.                 ISite site = ((IComponent)component).Site;
  844.                 if (site != null && site.DesignMode) {
  845.                     IDesignerHost host = (IDesignerHost)site.GetService(typeof(IDesignerHost));
  846.                     if (host != null) {
  847.                         object designer = host.GetDesigner((IComponent)component);
  848.                        
  849.                         // We only use the designer if it has a compatible class. If we
  850.                         // got here, we're probably hosed because the user just passed in
  851.                         // an object that this PropertyDescriptor can't munch on, but it's
  852.                         // clearer to use that object instance instead of it's designer.
  853.                         //
  854.                         if (designer != null && componentClass.IsInstanceOfType(designer)) {
  855.                             component = designer;
  856.                         }
  857.                     }
  858.                 }
  859.             }
  860.            
  861.             Debug.Assert(component != null, "Attempt to invoke on null component");
  862.             return component;
  863.         }
  864.        
  865.         /// <devdoc>
  866.         /// <para>
  867.         /// Gets an editor of the specified type.
  868.         /// </para>
  869.         /// </devdoc>
  870.         public override object GetEditor(Type editorBaseType)
  871.         {
  872.             object editor = null;
  873.            
  874.             // Check the editors we've already created for this type.
  875.             //
  876.             if (editorTypes != null) {
  877.                 for (int i = 0; i < editorCount; i++) {
  878.                     if (editorTypes[i] == editorBaseType) {
  879.                         return editors[i];
  880.                     }
  881.                 }
  882.             }
  883.            
  884.             // If one wasn't found, then we must go through the attributes.
  885.             //
  886.             if (editor == null) {
  887.                 for (int i = 0; i < Attributes.Count; i++) {
  888.                    
  889.                     if (!(Attributes[i] is EditorAttribute)) {
  890.                         continue;
  891.                     }
  892.                    
  893.                     EditorAttribute attr = (EditorAttribute)Attributes[i];
  894.                     Type editorType = GetTypeFromName(attr.EditorBaseTypeName);
  895.                    
  896.                     if (editorBaseType == editorType) {
  897.                         Type type = GetTypeFromName(attr.EditorTypeName);
  898.                         if (type != null) {
  899.                             editor = CreateInstance(type);
  900.                             break;
  901.                         }
  902.                     }
  903.                 }
  904.                
  905.                 // Now, if we failed to find it in our own attributes, go to the
  906.                 // component descriptor.
  907.                 //
  908.                 if (editor == null) {
  909.                     editor = DebugTypeDescriptor.GetEditor(PropertyType, editorBaseType);
  910.                 }
  911.                
  912.                 // Now, another slot in our editor cache for next time
  913.                 //
  914.                 if (editorTypes == null) {
  915.                     editorTypes = new Type[5];
  916.                     editors = new object[5];
  917.                 }
  918.                
  919.                 if (editorCount >= editorTypes.Length) {
  920.                     Type[] newTypes = new Type[editorTypes.Length * 2];
  921.                     object[] newEditors = new object[editors.Length * 2];
  922.                     Array.Copy(editorTypes, newTypes, editorTypes.Length);
  923.                     Array.Copy(editors, newEditors, editors.Length);
  924.                     editorTypes = newTypes;
  925.                     editors = newEditors;
  926.                 }
  927.                
  928.                 editorTypes[editorCount] = editorBaseType;
  929.                 editors[editorCount++] = editor;
  930.             }
  931.            
  932.             return editor;
  933.         }
  934.        
  935.         /// <devdoc>
  936.         /// Retrieves the current value of the property on component,
  937.         /// invoking the getXXX method. An exception in the getXXX
  938.         /// method will pass through.
  939.         /// </devdoc>
  940.         public override object GetValue(object component)
  941.         {
  942.             #if DEBUG
  943.             if (PropDescUsageSwitch.TraceVerbose) {
  944.                 string compName = "(null)";
  945.                 if (component != null)
  946.                     compName = component.ToString();
  947.                
  948.                 Debug.WriteLine("[" + Name + "]: GetValue(" + compName + ")");
  949.             }
  950.             #endif
  951.            
  952.             if (IsExtender) {
  953.                 Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
  954.                 return null;
  955.             }
  956.            
  957.             Debug.Assert(component != null, "GetValue must be given a component");
  958.            
  959.             if (component != null) {
  960.                 component = GetDebugInvokee(componentClass, component);
  961.                
  962.                
  963.                 try {
  964.                     return GetMethodValue.Invoke(component, null);
  965.                 }
  966.                 catch (Exception t) {
  967.                    
  968.                     string name = null;
  969.                     if (component is IComponent) {
  970.                        
  971.                         ISite site = ((IComponent)component).Site;
  972.                         if (site != null && site.Name != null) {
  973.                             name = site.Name;
  974.                         }
  975.                     }
  976.                    
  977.                     if (name == null) {
  978.                         name = component.GetType().FullName;
  979.                     }
  980.                    
  981.                     if (t is TargetInvocationException) {
  982.                         t = t.InnerException;
  983.                     }
  984.                    
  985.                     string message = t.Message;
  986.                     if (message == null) {
  987.                         message = t.GetType().Name;
  988.                     }
  989.                    
  990.                     throw new TargetInvocationException(SR.GetString(SR.ErrorPropertyAccessorException, Name, name, message), t);
  991.                 }
  992.                 catch {
  993.                     throw;
  994.                 }
  995.             }
  996.             Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
  997.             return null;
  998.         }
  999.        
  1000.         /// <devdoc>
  1001.         /// This should be called by your property descriptor implementation
  1002.         /// when the property value has changed.
  1003.         /// </devdoc>
  1004.         protected override void OnValueChanged(object component, EventArgs e)
  1005.         {
  1006.             if (state[BitChangedQueried] && realChangedEventInfo == null) {
  1007.                 base.OnValueChanged(component, e);
  1008.             }
  1009.         }
  1010.        
  1011.         /// <devdoc>
  1012.         /// Allows interested objects to be notified when this property changes.
  1013.         /// </devdoc>
  1014.         public override void RemoveValueChanged(object component, EventHandler handler)
  1015.         {
  1016.             if (component == null)
  1017.                 throw new ArgumentNullException("component");
  1018.             if (handler == null)
  1019.                 throw new ArgumentNullException("handler");
  1020.            
  1021.             EventInfo changedEvent = ChangedEventValue;
  1022.             if (changedEvent != null) {
  1023.                 changedEvent.RemoveEventHandler(component, handler);
  1024.             }
  1025.             else {
  1026.                 base.RemoveValueChanged(component, handler);
  1027.             }
  1028.         }
  1029.        
  1030.         /// <devdoc>
  1031.         /// Will reset the default value for this property on the component. If
  1032.         /// there was a default value passed in as a DefaultValueAttribute, that
  1033.         /// value will be set as the value of the property on the component. If
  1034.         /// there was no default value passed in, a ResetXXX method will be looked
  1035.         /// for. If one is found, it will be invoked. If one is not found, this
  1036.         /// is a nop.
  1037.         /// </devdoc>
  1038.         public override void ResetValue(object component)
  1039.         {
  1040.             object invokee = GetDebugInvokee(componentClass, component);
  1041.            
  1042.             if (DefaultValue != noValue) {
  1043.                 SetValue(component, DefaultValue);
  1044.             }
  1045.             else if (AmbientValue != noValue) {
  1046.                 SetValue(component, AmbientValue);
  1047.             }
  1048.             else if (ResetMethodValue != null) {
  1049.                 ISite site = GetSite(component);
  1050.                 IComponentChangeService changeService = null;
  1051.                 object oldValue = null;
  1052.                 object newValue;
  1053.                
  1054.                 // Announce that we are about to change this component
  1055.                 //
  1056.                 if (site != null) {
  1057.                     changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
  1058.                     Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
  1059.                 }
  1060.                
  1061.                 // Make sure that it is ok to send the onchange events
  1062.                 //
  1063.                 if (changeService != null) {
  1064.                     oldValue = GetMethodValue.Invoke(invokee, (object[])null);
  1065.                     try {
  1066.                         changeService.OnComponentChanging(component, this);
  1067.                     }
  1068.                     catch (CheckoutException coEx) {
  1069.                         if (coEx == CheckoutException.Canceled) {
  1070.                             return;
  1071.                         }
  1072.                         throw coEx;
  1073.                     }
  1074.                     catch {
  1075.                         throw;
  1076.                     }
  1077.                    
  1078.                 }
  1079.                
  1080.                 if (ResetMethodValue != null) {
  1081.                     ResetMethodValue.Invoke(invokee, (object[])null);
  1082.                    
  1083.                     // Now notify the change service that the change was successful.
  1084.                     //
  1085.                     if (changeService != null) {
  1086.                         newValue = GetMethodValue.Invoke(invokee, (object[])null);
  1087.                         changeService.OnComponentChanged(component, this, oldValue, newValue);
  1088.                     }
  1089.                 }
  1090.             }
  1091.         }
  1092.        
  1093.         /// <devdoc>
  1094.         /// This will set value to be the new value of this property on the
  1095.         /// component by invoking the setXXX method on the component. If the
  1096.         /// value specified is invalid, the component should throw an exception
  1097.         /// which will be passed up. The component designer should design the
  1098.         /// property so that getXXX following a setXXX should return the value
  1099.         /// passed in if no exception was thrown in the setXXX call.
  1100.         /// </devdoc>
  1101.         public override void SetValue(object component, object value)
  1102.         {
  1103.             #if DEBUG
  1104.             if (PropDescUsageSwitch.TraceVerbose) {
  1105.                 string compName = "(null)";
  1106.                 string valName = "(null)";
  1107.                
  1108.                 if (component != null)
  1109.                     compName = component.ToString();
  1110.                 if (value != null)
  1111.                     valName = value.ToString();
  1112.                
  1113.                 Debug.WriteLine("[" + Name + "]: SetValue(" + compName + ", " + valName + ")");
  1114.             }
  1115.             #endif
  1116.             if (component != null) {
  1117.                 ISite site = GetSite(component);
  1118.                 IComponentChangeService changeService = null;
  1119.                 object oldValue = null;
  1120.                
  1121.                 object invokee = GetDebugInvokee(componentClass, component);
  1122.                
  1123.                 Debug.Assert(!IsReadOnly, "SetValue attempted on read-only property [" + Name + "]");
  1124.                 if (!IsReadOnly) {
  1125.                    
  1126.                     // Announce that we are about to change this component
  1127.                     //
  1128.                     if (site != null) {
  1129.                         changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
  1130.                         Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
  1131.                     }
  1132.                    
  1133.                    
  1134.                     // Make sure that it is ok to send the onchange events
  1135.                     //
  1136.                     if (changeService != null) {
  1137.                         oldValue = GetMethodValue.Invoke(invokee, null);
  1138.                         try {
  1139.                             changeService.OnComponentChanging(component, this);
  1140.                         }
  1141.                         catch (CheckoutException coEx) {
  1142.                             if (coEx == CheckoutException.Canceled) {
  1143.                                 return;
  1144.                             }
  1145.                             throw coEx;
  1146.                         }
  1147.                     }
  1148.                    
  1149.                     try {
  1150.                         try {
  1151.                             SetMethodValue.Invoke(invokee, new object[] {value});
  1152.                             OnValueChanged(invokee, EventArgs.Empty);
  1153.                         }
  1154.                         catch (Exception t) {
  1155.                             value = oldValue;
  1156.                            
  1157.                             // If there was a problem setting the controls property then we get:
  1158.                             // ArgumentException (from properties set method)
  1159.                             // ==> Becomes inner exception of TargetInvocationException
  1160.                             // ==> caught here
  1161.                            
  1162.                             if (t is TargetInvocationException && t.InnerException != null) {
  1163.                                 // Propagate the original exception up
  1164.                                 throw t.InnerException;
  1165.                             }
  1166.                             else {
  1167.                                 throw t;
  1168.                             }
  1169.                         }
  1170.                         catch {
  1171.                             throw;
  1172.                         }
  1173.                     }
  1174.                     finally {
  1175.                         // Now notify the change service that the change was successful.
  1176.                         //
  1177.                         if (changeService != null) {
  1178.                             changeService.OnComponentChanged(component, this, oldValue, value);
  1179.                         }
  1180.                     }
  1181.                 }
  1182.             }
  1183.         }
  1184.        
  1185.         /// <devdoc>
  1186.         /// Indicates whether the value of this property needs to be persisted. In
  1187.         /// other words, it indicates whether the state of the property is distinct
  1188.         /// from when the component is first instantiated. If there is a default
  1189.         /// value specified in this DebugReflectPropertyDescriptor, it will be compared against the
  1190.         /// property's current value to determine this. If there is't, the
  1191.         /// ShouldSerializeXXX method is looked for and invoked if found. If both
  1192.         /// these routes fail, true will be returned.
  1193.         ///
  1194.         /// If this returns false, a tool should not persist this property's value.
  1195.         /// </devdoc>
  1196.         public override bool ShouldSerializeValue(object component)
  1197.         {
  1198.            
  1199.             component = GetDebugInvokee(componentClass, component);
  1200.            
  1201.             if (IsReadOnly) {
  1202.                 if (ShouldSerializeMethodValue != null) {
  1203.                     try {
  1204.                         return (bool)ShouldSerializeMethodValue.Invoke(component, null);
  1205.                     }
  1206.                     catch {
  1207.                     }
  1208.                 }
  1209.                 return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
  1210.             }
  1211.             else if (DefaultValue == noValue) {
  1212.                 if (ShouldSerializeMethodValue != null) {
  1213.                     try {
  1214.                         return (bool)ShouldSerializeMethodValue.Invoke(component, null);
  1215.                     }
  1216.                     catch {
  1217.                     }
  1218.                 }
  1219.                 return true;
  1220.             }
  1221.             return !object.Equals(DefaultValue, GetValue(component));
  1222.         }
  1223.        
  1224.        
  1225.         /*
  1226.             The following code has been removed to fix FXCOP violations.  The code
  1227.             is left here incase it needs to be resurrected in the future.
  1228.         /// <devdoc>
  1229.         ///    A constructor for ReflectPropertyDescriptors that have no attributes.
  1230.         /// </devdoc>
  1231.         public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type) : this(componentClass, name, type, (Attribute[])null) {
  1232.         }
  1233.         */       
  1234.     }
  1235. }
  1236. #endif

Developer Fusion