1 //------------------------------------------------------------------------------
2 // <copyright file="DebugReflectPropertyDescriptor.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
11 This class exists in debug only. It is a complete copy of the
12 V1.0 TypeDescriptor object and is used to validate that the
13 behavior of the V2.0 TypeDescriptor matches 1.0 behavior.
16 namespace System.ComponentModel {
17 using System.Runtime.Serialization.Formatters;
18 using System.Runtime.InteropServices;
19 using System.Diagnostics;
21 using System.Collections;
22 using System.Collections.Specialized;
23 using System.Reflection;
24 using Microsoft.Win32;
25 using System.Security;
26 using System.Security.Permissions;
27 using System.ComponentModel.Design;
28 using System.ComponentModel;
33 /// DebugReflectPropertyDescriptor defines a property. Properties are the main way that a user can
34 /// set up the state of a component.
35 /// The DebugReflectPropertyDescriptor class takes a component class that the property lives on,
36 /// a property name, the type of the property, and various attributes for the
38 /// For a property named XXX of type YYY, the associated component class is
39 /// required to implement two methods of the following
43 /// public YYY GetXXX();
44 /// public void SetXXX(YYY value);
46 /// The component class can optionally implement two additional methods of
47 /// the following form:
49 /// public boolean ShouldSerializeXXX();
50 /// public void ResetXXX();
52 /// These methods deal with a property's default value. The ShouldSerializeXXX()
53 /// method returns true if the current value of the XXX property is different
54 /// than it's default value, so that it should be persisted out. The ResetXXX()
55 /// method resets the XXX property to its default value. If the DebugReflectPropertyDescriptor
56 /// includes the default value of the property (using the DefaultValueAttribute),
57 /// the ShouldSerializeXXX() and ResetXXX() methods are ignored.
58 /// If the DebugReflectPropertyDescriptor includes a reference to an editor
59 /// then that value editor will be used to
60 /// edit the property. Otherwise, a system-provided editor will be used.
61 /// Various attributes can be passed to the DebugReflectPropertyDescriptor, as are described in
63 /// ReflectPropertyDescriptors can be obtained by a user programmatically through the
66 [HostProtection(SharedState = true)]
67 internal sealed class DebugReflectPropertyDescriptor : PropertyDescriptor {
69 private static readonly Type[] argsNone = new Type[0];
70 private static readonly object noValue = new object();
72 private static TraceSwitch PropDescCreateSwitch = new TraceSwitch("PropDescCreate", "DebugReflectPropertyDescriptor: Dump errors when creating property info");
73 private static TraceSwitch PropDescUsageSwitch = new TraceSwitch("PropDescUsage", "DebugReflectPropertyDescriptor: Debug propertydescriptor usage");
74 private static TraceSwitch PropDescSwitch = new TraceSwitch("PropDesc", "DebugReflectPropertyDescriptor: Debug property descriptor");
76 private static readonly int BitDefaultValueQueried = BitVector32.CreateMask();
77 private static readonly int BitGetQueried = BitVector32.CreateMask(BitDefaultValueQueried);
78 private static readonly int BitSetQueried = BitVector32.CreateMask(BitGetQueried);
79 private static readonly int BitShouldSerializeQueried = BitVector32.CreateMask(BitSetQueried);
80 private static readonly int BitResetQueried = BitVector32.CreateMask(BitShouldSerializeQueried);
81 private static readonly int BitChangedQueried = BitVector32.CreateMask(BitResetQueried);
82 private static readonly int BitReadOnlyChecked = BitVector32.CreateMask(BitChangedQueried);
83 private static readonly int BitAmbientValueQueried = BitVector32.CreateMask(BitReadOnlyChecked);
85 internal BitVector32 state = new BitVector32(); // Contains the state bits for this proeprty descriptor.
86 Type componentClass; // used to determine if we should all on us or on the designer
87 Type type; // the data type of the property
89 internal object defaultValue; // the default value of the property (or noValue)
90 internal object ambientValue; // the ambient value of the property (or noValue)
92 internal PropertyInfo propInfo; // the property info
93 internal MethodInfo getMethod; // the property get method
94 internal MethodInfo setMethod; // the property set method
96 internal MethodInfo shouldSerializeMethod; // the should serialize method
97 internal MethodInfo resetMethod; // the reset property method
99 EventInfo realChangedEventInfo; // Changed event handler on object
101 Type receiverType; // Only set if we are an extender
102 private TypeConverter converter;
103 private object[] editors;
104 private Type[] editorTypes;
105 private int editorCount;
108 /// The main constructor for ReflectPropertyDescriptors.
110 public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type,
111 Attribute[] attributes)
112 : base(name, attributes) {
114 Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "Creating DebugReflectPropertyDescriptor for " + componentClass.FullName + "." + name);
118 Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "type == null, name == " + name);
119 throw new ArgumentException(SR.GetString(SR.ErrorInvalidPropertyType, name));
121 if (componentClass == null) {
122 Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "componentClass == null, name == " + name);
123 throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
126 this.componentClass = componentClass;
128 catch (Exception t) {
129 Debug.Fail("Property '" + name + "' on component " + componentClass.FullName + " failed to init.");
130 Debug.Fail(t.ToString());
136 /// A constructor for ReflectPropertyDescriptors that have no attributes.
138 public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type, PropertyInfo propInfo, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs) {
139 this.propInfo = propInfo;
140 this.getMethod = getMethod;
141 this.setMethod = setMethod;
142 state[BitGetQueried | BitSetQueried] = true;
146 /// A constructor for ReflectPropertyDescriptors that creates an extender property.
148 public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type, Type receiverType, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs) {
149 this.receiverType = receiverType;
150 this.getMethod = getMethod;
151 this.setMethod = setMethod;
152 state[BitGetQueried | BitSetQueried] = true;
156 /// This constructor takes an existing DebugReflectPropertyDescriptor and modifies it by merging in the
157 /// passed-in attributes.
159 public DebugReflectPropertyDescriptor(Type componentClass, PropertyDescriptor oldReflectPropertyDescriptor, Attribute[] attributes)
160 : base(oldReflectPropertyDescriptor, attributes) {
162 this.componentClass = componentClass;
163 this.type = oldReflectPropertyDescriptor.PropertyType;
165 if (componentClass == null) {
166 throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
169 // If the classes are the same, we can potentially optimize the method fetch because
170 // the old property descriptor may already have it.
172 if (oldReflectPropertyDescriptor is DebugReflectPropertyDescriptor) {
173 DebugReflectPropertyDescriptor oldProp = (DebugReflectPropertyDescriptor)oldReflectPropertyDescriptor;
175 if (oldProp.ComponentType == componentClass) {
176 propInfo = oldProp.propInfo;
177 getMethod = oldProp.getMethod;
178 setMethod = oldProp.setMethod;
179 shouldSerializeMethod = oldProp.shouldSerializeMethod;
180 resetMethod = oldProp.resetMethod;
181 defaultValue = oldProp.defaultValue;
182 ambientValue = oldProp.ambientValue;
183 state = oldProp.state;
186 // Now we must figure out what to do with our default value. First, check to see
187 // if the caller has provided an new default value attribute. If so, use it. Otherwise,
188 // just let it be and it will be picked up on demand.
190 if (attributes != null) {
191 foreach(Attribute a in attributes) {
192 if (a is DefaultValueAttribute) {
193 defaultValue = ((DefaultValueAttribute)a).Value;
194 state[BitDefaultValueQueried] = true;
196 else if (a is AmbientValueAttribute) {
197 ambientValue = ((AmbientValueAttribute)a).Value;
198 state[BitAmbientValueQueried] = true;
206 /// Retrieves the ambient value for this property.
208 private object AmbientValue {
210 if (!state[BitAmbientValueQueried]) {
211 state[BitAmbientValueQueried] = true;
212 Attribute a = Attributes[typeof(AmbientValueAttribute)];
214 ambientValue = ((AmbientValueAttribute)a).Value;
217 ambientValue = noValue;
225 /// The EventInfo for the changed event on the component, or null if there isn't one for this property.
227 private EventInfo ChangedEventValue {
229 if (!state[BitChangedQueried]) {
230 state[BitChangedQueried] = true;
231 realChangedEventInfo = ComponentType.GetEvent(Name + "Changed", BindingFlags.Public | BindingFlags.Instance);
233 return realChangedEventInfo;
237 The following code has been removed to fix FXCOP violations. The code
238 is left here incase it needs to be resurrected in the future.
241 realChangedEventInfo = value;
242 state[BitChangedQueried] = true;
248 /// Retrieves the type of the component this PropertyDescriptor is bound to.
250 public override Type ComponentType {
252 return componentClass;
258 /// Gets the type converter for this property.
261 public override TypeConverter Converter {
263 if (converter == null) {
264 TypeConverterAttribute attr = (TypeConverterAttribute)Attributes[typeof(TypeConverterAttribute)];
265 if (attr.ConverterTypeName != null && attr.ConverterTypeName.Length > 0) {
266 Type converterType = GetTypeFromName(attr.ConverterTypeName);
267 if (converterType != null && typeof(TypeConverter).IsAssignableFrom(converterType)) {
268 converter = (TypeConverter)CreateInstance(converterType);
272 if (converter == null) {
273 converter = DebugTypeDescriptor.GetConverter(PropertyType);
281 /// Retrieves the default value for this property.
283 private object DefaultValue {
285 if (!state[BitDefaultValueQueried]) {
286 state[BitDefaultValueQueried] = true;
287 Attribute a = Attributes[typeof(DefaultValueAttribute)];
289 defaultValue = ((DefaultValueAttribute)a).Value;
292 defaultValue = noValue;
300 /// The GetMethod for this property
302 private MethodInfo GetMethodValue {
304 if (!state[BitGetQueried]) {
305 state[BitGetQueried] = true;
307 if (receiverType == null) {
308 if (propInfo == null) {
309 BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
310 propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
312 if (propInfo != null) {
313 getMethod = propInfo.GetGetMethod(true);
315 if (getMethod == null) {
316 throw new InvalidOperationException(SR.GetString(SR.ErrorMissingPropertyAccessors, componentClass.FullName + "." + Name));
320 getMethod = FindMethod(componentClass, "Get" + Name, new Type[] {receiverType}, type);
321 if (getMethod == null) {
322 throw new ArgumentException(SR.GetString(SR.ErrorMissingPropertyAccessors, Name));
330 The following code has been removed to fix FXCOP violations. The code
331 is left here incase it needs to be resurrected in the future.
334 state[BitGetQueried] = true;
341 /// Determines if this property is an extender property.
343 private bool IsExtender {
345 return (receiverType != null);
350 /// Indicates whether this property is read only.
352 public override bool IsReadOnly {
354 return SetMethodValue == null || ((ReadOnlyAttribute)Attributes[typeof(ReadOnlyAttribute)]).IsReadOnly;
359 /// Retrieves the type of the property.
361 public override Type PropertyType {
368 /// Access to the reset method, if one exists for this property.
370 private MethodInfo ResetMethodValue {
372 if (!state[BitResetQueried]) {
373 state[BitResetQueried] = true;
377 if (receiverType == null) {
381 args = new Type[] {receiverType};
384 IntSecurity.FullReflection.Assert();
387 resetMethod = FindMethod(componentClass, "Reset" + Name, args, typeof(void), /* publicOnly= */ false);
390 CodeAccessPermission.RevertAssert();
397 The following code has been removed to fix FXCOP violations. The code
398 is left here incase it needs to be resurrected in the future.
401 state[BitResetQueried] = true;
408 /// Accessor for the set method
410 private MethodInfo SetMethodValue {
412 if (!state[BitSetQueried]) {
413 state[BitSetQueried] = true;
415 if (receiverType == null) {
416 if (propInfo == null) {
417 BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
418 propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
420 if (propInfo != null) {
421 setMethod = propInfo.GetSetMethod(true);
425 setMethod = FindMethod(componentClass, "Set" + Name,
426 new Type[] { receiverType, type}, typeof(void));
433 The following code has been removed to fix FXCOP violations. The code
434 is left here incase it needs to be resurrected in the future.
437 state[BitSetQueried] = true;
444 /// Accessor for the ShouldSerialize method.
446 private MethodInfo ShouldSerializeMethodValue {
448 if (!state[BitShouldSerializeQueried]) {
449 state[BitShouldSerializeQueried] = true;
453 if (receiverType == null) {
457 args = new Type[] {receiverType};
460 IntSecurity.FullReflection.Assert();
463 shouldSerializeMethod = FindMethod(componentClass, "ShouldSerialize" + Name,
464 args, typeof(Boolean), /* publicOnly= */ false);
467 CodeAccessPermission.RevertAssert();
470 return shouldSerializeMethod;
474 The following code has been removed to fix FXCOP violations. The code
475 is left here incase it needs to be resurrected in the future.
478 state[BitShouldSerializeQueried] = true;
479 shouldSerializeMethod = value;
485 /// Allows interested objects to be notified when this property changes.
487 public override void AddValueChanged(object component, EventHandler handler) {
488 if (component == null) throw new ArgumentNullException("component");
489 if (handler == null) throw new ArgumentNullException("handler");
491 EventInfo changedEvent = ChangedEventValue;
492 if (changedEvent != null) {
493 changedEvent.AddEventHandler(component, handler);
496 base.AddValueChanged(component, handler);
500 internal bool ExtenderCanResetValue(IExtenderProvider provider, object component) {
501 if (DefaultValue != noValue) {
502 return !object.Equals(ExtenderGetValue(provider, component),defaultValue);
505 MethodInfo reset = ResetMethodValue;
507 MethodInfo shouldSerialize = ShouldSerializeMethodValue;
508 if (shouldSerialize != null) {
510 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
511 return (bool)shouldSerialize.Invoke(provider, new object[] { component});
522 internal Type ExtenderGetReceiverType() {
526 internal Type ExtenderGetType(IExtenderProvider provider) {
530 internal object ExtenderGetValue(IExtenderProvider provider, object component) {
531 if (provider != null) {
532 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
533 return GetMethodValue.Invoke(provider, new object[] { component});
538 internal void ExtenderResetValue(IExtenderProvider provider, object component, PropertyDescriptor notifyDesc) {
539 if (DefaultValue != noValue) {
540 ExtenderSetValue(provider, component, DefaultValue, notifyDesc);
542 else if (AmbientValue != noValue) {
543 ExtenderSetValue(provider, component, AmbientValue, notifyDesc);
545 else if (ResetMethodValue != null) {
546 ISite site = GetSite(component);
547 IComponentChangeService changeService = null;
548 object oldValue = null;
551 // Announce that we are about to change this component
554 changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
555 Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
558 // Make sure that it is ok to send the onchange events
560 if (changeService != null) {
561 oldValue = ExtenderGetValue(provider, component);
563 changeService.OnComponentChanging(component, notifyDesc);
565 catch (CheckoutException coEx) {
566 if (coEx == CheckoutException.Canceled) {
573 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
574 if (ResetMethodValue != null) {
575 ResetMethodValue.Invoke(provider, new object[] { component});
577 // Now notify the change service that the change was successful.
579 if (changeService != null) {
580 newValue = ExtenderGetValue(provider, component);
581 changeService.OnComponentChanged(component, notifyDesc, oldValue, newValue);
587 internal void ExtenderSetValue(IExtenderProvider provider, object component, object value, PropertyDescriptor notifyDesc) {
588 if (provider != null) {
590 ISite site = GetSite(component);
591 IComponentChangeService changeService = null;
592 object oldValue = null;
594 // Announce that we are about to change this component
597 changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
598 Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
601 // Make sure that it is ok to send the onchange events
603 if (changeService != null) {
604 oldValue = ExtenderGetValue(provider, component);
606 changeService.OnComponentChanging(component, notifyDesc);
608 catch (CheckoutException coEx) {
609 if (coEx == CheckoutException.Canceled) {
616 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
618 if (SetMethodValue != null) {
619 SetMethodValue.Invoke(provider, new object[] { component, value});
621 // Now notify the change service that the change was successful.
623 if (changeService != null) {
624 changeService.OnComponentChanged(component, notifyDesc, oldValue, value);
630 internal bool ExtenderShouldSerializeValue(IExtenderProvider provider, object component) {
633 provider = (IExtenderProvider)GetDebugInvokee(componentClass, provider);
636 if (ShouldSerializeMethodValue != null) {
638 return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
642 return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
644 else if (DefaultValue == noValue) {
645 if (ShouldSerializeMethodValue != null) {
647 return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
653 return !object.Equals(DefaultValue, ExtenderGetValue(provider, component));
657 /// Indicates whether reset will change the value of the component. If there
658 /// is a DefaultValueAttribute, then this will return true if getValue returns
659 /// something different than the default value. If there is a reset method and
660 /// a ShouldSerialize method, this will return what ShouldSerialize returns.
661 /// If there is just a reset method, this always returns true. If none of these
662 /// cases apply, this returns false.
664 public override bool CanResetValue(object component) {
669 if (DefaultValue != noValue) {
670 return !object.Equals(GetValue(component),DefaultValue);
673 if (ResetMethodValue != null) {
674 if (ShouldSerializeMethodValue != null) {
675 component = GetDebugInvokee(componentClass, component);
677 return (bool)ShouldSerializeMethodValue.Invoke(component, null);
684 if (AmbientValue != noValue) {
685 return ShouldSerializeValue(component);
691 protected override void FillAttributes(IList attributes) {
692 Debug.Assert(componentClass != null, "Must have a component class for FillAttributes");
695 // The order that we fill in attributes is critical. The list of attributes will be
696 // filtered so that matching attributes at the end of the list replace earlier matches
697 // (last one in wins). Therefore, the three categories of attributes we add must be
700 // 1. Attributes of the property type. These are the lowest level and should be
701 // overwritten by any newer attributes.
703 // 2. Attributes of the property itself, from base class to most derived. This way
704 // derived class attributes replace base class attributes.
706 // 3. Attributes from our base MemberDescriptor. While this seems opposite of what
707 // we want, MemberDescriptor only has attributes if someone passed in a new
708 // set in the constructor. Therefore, these attributes always
709 // supercede existing values.
713 // We need to include attributes from the type of the property.
715 foreach (Attribute typeAttr in DebugTypeDescriptor.GetAttributes(PropertyType)) {
716 attributes.Add(typeAttr);
719 // NOTE : Must look at method OR property, to handle the case of Extender properties...
721 // Note : Because we are using BindingFlags.DeclaredOnly it is more effcient to re-aquire
722 // : the property info, rather than use the one we have cached. The one we have cached
723 // : may ave come from a base class, meaning we will request custom metadata for this
726 BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;
727 Type currentReflectType = componentClass;
730 // First, calculate the depth of the object hierarchy. We do this so we can do a single
731 // object create for an array of attributes.
733 while(currentReflectType != null && currentReflectType != typeof(object)) {
735 currentReflectType = currentReflectType.BaseType;
738 // Now build up an array in reverse order
741 currentReflectType = componentClass;
742 object[][] attributeStack = new object[depth][];
744 while(currentReflectType != null && currentReflectType != typeof(object)) {
746 MemberInfo memberInfo = null;
748 // Fill in our member info so we can get at the custom attributes.
751 memberInfo = currentReflectType.GetMethod("Get" + Name, bindingFlags);
754 memberInfo = currentReflectType.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
757 // Get custom attributes for the member info.
759 if (memberInfo != null) {
760 attributeStack[--depth] = DebugTypeDescriptor.GetCustomAttributes(memberInfo);
763 // Ready for the next loop iteration.
765 currentReflectType = currentReflectType.BaseType;
768 // Now trawl the attribute stack so that we add attributes
769 // from base class to most derived.
771 foreach(object[] attributeArray in attributeStack) {
772 if (attributeArray != null) {
773 foreach(object attr in attributeArray) {
774 if (attr is Attribute) {
775 attributes.Add(attr);
782 // Include the base attributes. These override all attributes on the actual
783 // property, so we want to add them last.
785 base.FillAttributes(attributes);
787 // Finally, override any form of ReadOnlyAttribute.
789 if (!state[BitReadOnlyChecked]) {
790 state[BitReadOnlyChecked] = true;
791 if (SetMethodValue == null) {
792 attributes.Add(ReadOnlyAttribute.Yes);
798 /// Retrieves the properties
800 public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter) {
801 if (instance == null) {
802 return DebugTypeDescriptor.GetProperties(PropertyType, filter);
805 return DebugTypeDescriptor.GetProperties(instance, filter);
813 /// that a method should be invoked on.
816 private static object GetDebugInvokee(Type componentClass, object component) {
818 // We delve into the component's designer only if it is a component and if
819 // the component we've been handed is not an instance of this property type.
821 if (!componentClass.IsInstanceOfType(component) && component is IComponent) {
822 ISite site = ((IComponent)component).Site;
823 if (site != null && site.DesignMode) {
824 IDesignerHost host = (IDesignerHost)site.GetService(typeof(IDesignerHost));
826 object designer = host.GetDesigner((IComponent)component);
828 // We only use the designer if it has a compatible class. If we
829 // got here, we're probably hosed because the user just passed in
830 // an object that this PropertyDescriptor can't munch on, but it's
831 // clearer to use that object instance instead of it's designer.
833 if (designer != null && componentClass.IsInstanceOfType(designer)) {
834 component = designer;
840 Debug.Assert(component != null, "Attempt to invoke on null component");
846 /// Gets an editor of the specified type.
849 public override object GetEditor(Type editorBaseType) {
850 object editor = null;
852 // Check the editors we've already created for this type.
854 if (editorTypes != null) {
855 for (int i = 0; i < editorCount; i++) {
856 if (editorTypes[i] == editorBaseType) {
862 // If one wasn't found, then we must go through the attributes.
864 if (editor == null) {
865 for (int i = 0; i < Attributes.Count; i++) {
867 if (!(Attributes[i] is EditorAttribute)) {
871 EditorAttribute attr = (EditorAttribute)Attributes[i];
872 Type editorType = GetTypeFromName(attr.EditorBaseTypeName);
874 if (editorBaseType == editorType) {
875 Type type = GetTypeFromName(attr.EditorTypeName);
877 editor = CreateInstance(type);
883 // Now, if we failed to find it in our own attributes, go to the
884 // component descriptor.
886 if (editor == null) {
887 editor = DebugTypeDescriptor.GetEditor(PropertyType, editorBaseType);
890 // Now, another slot in our editor cache for next time
892 if (editorTypes == null) {
893 editorTypes = new Type[5];
894 editors = new object[5];
897 if (editorCount >= editorTypes.Length) {
898 Type[] newTypes = new Type[editorTypes.Length * 2];
899 object[] newEditors = new object[editors.Length * 2];
900 Array.Copy(editorTypes, newTypes, editorTypes.Length);
901 Array.Copy(editors, newEditors, editors.Length);
902 editorTypes = newTypes;
903 editors = newEditors;
906 editorTypes[editorCount] = editorBaseType;
907 editors[editorCount++] = editor;
914 /// Retrieves the current value of the property on component,
915 /// invoking the getXXX method. An exception in the getXXX
916 /// method will pass through.
918 public override object GetValue(object component) {
920 if (PropDescUsageSwitch.TraceVerbose) {
921 string compName = "(null)";
922 if (component != null)
923 compName = component.ToString();
925 Debug.WriteLine("[" + Name + "]: GetValue(" + compName + ")");
930 Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
934 Debug.Assert(component != null, "GetValue must be given a component");
936 if (component != null) {
937 component = GetDebugInvokee(componentClass, component);
941 return GetMethodValue.Invoke(component, null);
943 catch (Exception t) {
946 if (component is IComponent) {
948 ISite site = ((IComponent)component).Site;
949 if (site != null && site.Name != null) {
955 name = component.GetType().FullName;
958 if (t is TargetInvocationException) {
959 t = t.InnerException;
962 string message = t.Message;
963 if (message == null) {
964 message = t.GetType().Name;
967 throw new TargetInvocationException(SR.GetString(SR.ErrorPropertyAccessorException, Name, name, message), t);
970 Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
975 /// This should be called by your property descriptor implementation
976 /// when the property value has changed.
978 protected override void OnValueChanged(object component, EventArgs e) {
979 if (state[BitChangedQueried] && realChangedEventInfo == null) {
980 base.OnValueChanged(component, e);
985 /// Allows interested objects to be notified when this property changes.
987 public override void RemoveValueChanged(object component, EventHandler handler) {
988 if (component == null) throw new ArgumentNullException("component");
989 if (handler == null) throw new ArgumentNullException("handler");
991 EventInfo changedEvent = ChangedEventValue;
992 if (changedEvent != null) {
993 changedEvent.RemoveEventHandler(component, handler);
996 base.RemoveValueChanged(component, handler);
1001 /// Will reset the default value for this property on the component. If
1002 /// there was a default value passed in as a DefaultValueAttribute, that
1003 /// value will be set as the value of the property on the component. If
1004 /// there was no default value passed in, a ResetXXX method will be looked
1005 /// for. If one is found, it will be invoked. If one is not found, this
1008 public override void ResetValue(object component) {
1009 object invokee = GetDebugInvokee(componentClass, component);
1011 if (DefaultValue != noValue) {
1012 SetValue(component, DefaultValue);
1014 else if (AmbientValue != noValue) {
1015 SetValue(component, AmbientValue);
1017 else if (ResetMethodValue != null) {
1018 ISite site = GetSite(component);
1019 IComponentChangeService changeService = null;
1020 object oldValue = null;
1023 // Announce that we are about to change this component
1026 changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
1027 Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
1030 // Make sure that it is ok to send the onchange events
1032 if (changeService != null) {
1033 oldValue = GetMethodValue.Invoke(invokee, (object[])null);
1035 changeService.OnComponentChanging(component, this);
1037 catch (CheckoutException coEx) {
1038 if (coEx == CheckoutException.Canceled) {
1049 if (ResetMethodValue != null) {
1050 ResetMethodValue.Invoke(invokee, (object[])null);
1052 // Now notify the change service that the change was successful.
1054 if (changeService != null) {
1055 newValue = GetMethodValue.Invoke(invokee, (object[])null);
1056 changeService.OnComponentChanged(component, this, oldValue, newValue);
1063 /// This will set value to be the new value of this property on the
1064 /// component by invoking the setXXX method on the component. If the
1065 /// value specified is invalid, the component should throw an exception
1066 /// which will be passed up. The component designer should design the
1067 /// property so that getXXX following a setXXX should return the value
1068 /// passed in if no exception was thrown in the setXXX call.
1070 public override void SetValue(object component, object value) {
1072 if (PropDescUsageSwitch.TraceVerbose) {
1073 string compName = "(null)";
1074 string valName = "(null)";
1076 if (component != null)
1077 compName = component.ToString();
1079 valName = value.ToString();
1081 Debug.WriteLine("[" + Name + "]: SetValue(" + compName + ", " + valName + ")");
1084 if (component != null) {
1085 ISite site = GetSite(component);
1086 IComponentChangeService changeService = null;
1087 object oldValue = null;
1089 object invokee = GetDebugInvokee(componentClass, component);
1091 Debug.Assert(!IsReadOnly, "SetValue attempted on read-only property [" + Name + "]");
1094 // Announce that we are about to change this component
1097 changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
1098 Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
1102 // Make sure that it is ok to send the onchange events
1104 if (changeService != null) {
1105 oldValue = GetMethodValue.Invoke(invokee, null);
1107 changeService.OnComponentChanging(component, this);
1109 catch (CheckoutException coEx) {
1110 if (coEx == CheckoutException.Canceled) {
1119 SetMethodValue.Invoke(invokee, new object[]{value});
1120 OnValueChanged(invokee, EventArgs.Empty);
1122 catch (Exception t) {
1123 // Give ourselves a chance to unwind properly before rethrowing the exception (bug# 20221).
1127 // If there was a problem setting the controls property then we get:
1128 // ArgumentException (from properties set method)
1129 // ==> Becomes inner exception of TargetInvocationException
1132 if (t is TargetInvocationException && t.InnerException != null) {
1133 // Propagate the original exception up
1134 throw t.InnerException;
1142 // Now notify the change service that the change was successful.
1144 if (changeService != null) {
1145 changeService.OnComponentChanged(component, this, oldValue, value);
1153 /// Indicates whether the value of this property needs to be persisted. In
1154 /// other words, it indicates whether the state of the property is distinct
1155 /// from when the component is first instantiated. If there is a default
1156 /// value specified in this DebugReflectPropertyDescriptor, it will be compared against the
1157 /// property's current value to determine this. If there is't, the
1158 /// ShouldSerializeXXX method is looked for and invoked if found. If both
1159 /// these routes fail, true will be returned.
1161 /// If this returns false, a tool should not persist this property's value.
1163 public override bool ShouldSerializeValue(object component) {
1165 component = GetDebugInvokee(componentClass, component);
1168 if (ShouldSerializeMethodValue != null) {
1170 return (bool)ShouldSerializeMethodValue.Invoke(component, null);
1174 return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
1176 else if (DefaultValue == noValue) {
1177 if (ShouldSerializeMethodValue != null) {
1179 return (bool)ShouldSerializeMethodValue.Invoke(component, null);
1185 return !object.Equals(DefaultValue, GetValue(component));
1190 The following code has been removed to fix FXCOP violations. The code
1191 is left here incase it needs to be resurrected in the future.
1194 /// A constructor for ReflectPropertyDescriptors that have no attributes.
1196 public DebugReflectPropertyDescriptor(Type componentClass, string name, Type type) : this(componentClass, name, type, (Attribute[])null) {