1240 lines
55 KiB
C#
1240 lines
55 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="ReflectPropertyDescriptor.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
/*
|
||
|
*/
|
||
|
namespace System.ComponentModel {
|
||
|
using Microsoft.Win32;
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Collections.Specialized;
|
||
|
using System.ComponentModel.Design;
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.Reflection;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Runtime.Serialization.Formatters;
|
||
|
using System.Security;
|
||
|
using System.Security.Permissions;
|
||
|
|
||
|
/// <internalonly/>
|
||
|
/// <devdoc>
|
||
|
/// <para>
|
||
|
/// ReflectPropertyDescriptor defines a property. Properties are the main way that a user can
|
||
|
/// set up the state of a component.
|
||
|
/// The ReflectPropertyDescriptor class takes a component class that the property lives on,
|
||
|
/// a property name, the type of the property, and various attributes for the
|
||
|
/// property.
|
||
|
/// For a property named XXX of type YYY, the associated component class is
|
||
|
/// required to implement two methods of the following
|
||
|
/// form:
|
||
|
/// </para>
|
||
|
/// <code>
|
||
|
/// public YYY GetXXX();
|
||
|
/// public void SetXXX(YYY value);
|
||
|
/// </code>
|
||
|
/// The component class can optionally implement two additional methods of
|
||
|
/// the following form:
|
||
|
/// <code>
|
||
|
/// public boolean ShouldSerializeXXX();
|
||
|
/// public void ResetXXX();
|
||
|
/// </code>
|
||
|
/// These methods deal with a property's default value. The ShouldSerializeXXX()
|
||
|
/// method returns true if the current value of the XXX property is different
|
||
|
/// than it's default value, so that it should be persisted out. The ResetXXX()
|
||
|
/// method resets the XXX property to its default value. If the ReflectPropertyDescriptor
|
||
|
/// includes the default value of the property (using the DefaultValueAttribute),
|
||
|
/// the ShouldSerializeXXX() and ResetXXX() methods are ignored.
|
||
|
/// If the ReflectPropertyDescriptor includes a reference to an editor
|
||
|
/// then that value editor will be used to
|
||
|
/// edit the property. Otherwise, a system-provided editor will be used.
|
||
|
/// Various attributes can be passed to the ReflectPropertyDescriptor, as are described in
|
||
|
/// Attribute.
|
||
|
/// ReflectPropertyDescriptors can be obtained by a user programmatically through the
|
||
|
/// ComponentManager.
|
||
|
/// </devdoc>
|
||
|
[HostProtection(SharedState = true)]
|
||
|
internal sealed class ReflectPropertyDescriptor : PropertyDescriptor {
|
||
|
|
||
|
private static readonly Type[] argsNone = new Type[0];
|
||
|
private static readonly object noValue = new object();
|
||
|
|
||
|
private static TraceSwitch PropDescCreateSwitch = new TraceSwitch("PropDescCreate", "ReflectPropertyDescriptor: Dump errors when creating property info");
|
||
|
private static TraceSwitch PropDescUsageSwitch = new TraceSwitch("PropDescUsage", "ReflectPropertyDescriptor: Debug propertydescriptor usage");
|
||
|
private static TraceSwitch PropDescSwitch = new TraceSwitch("PropDesc", "ReflectPropertyDescriptor: Debug property descriptor");
|
||
|
|
||
|
private static readonly int BitDefaultValueQueried = BitVector32.CreateMask();
|
||
|
private static readonly int BitGetQueried = BitVector32.CreateMask(BitDefaultValueQueried);
|
||
|
private static readonly int BitSetQueried = BitVector32.CreateMask(BitGetQueried);
|
||
|
private static readonly int BitShouldSerializeQueried = BitVector32.CreateMask(BitSetQueried);
|
||
|
private static readonly int BitResetQueried = BitVector32.CreateMask(BitShouldSerializeQueried);
|
||
|
private static readonly int BitChangedQueried = BitVector32.CreateMask(BitResetQueried);
|
||
|
private static readonly int BitIPropChangedQueried = BitVector32.CreateMask(BitChangedQueried);
|
||
|
private static readonly int BitReadOnlyChecked = BitVector32.CreateMask(BitIPropChangedQueried);
|
||
|
private static readonly int BitAmbientValueQueried = BitVector32.CreateMask(BitReadOnlyChecked);
|
||
|
private static readonly int BitSetOnDemand = BitVector32.CreateMask(BitAmbientValueQueried);
|
||
|
|
||
|
|
||
|
BitVector32 state = new BitVector32(); // Contains the state bits for this proeprty descriptor.
|
||
|
Type componentClass; // used to determine if we should all on us or on the designer
|
||
|
Type type; // the data type of the property
|
||
|
object defaultValue; // the default value of the property (or noValue)
|
||
|
object ambientValue; // the ambient value of the property (or noValue)
|
||
|
PropertyInfo propInfo; // the property info
|
||
|
MethodInfo getMethod; // the property get method
|
||
|
MethodInfo setMethod; // the property set method
|
||
|
MethodInfo shouldSerializeMethod; // the should serialize method
|
||
|
MethodInfo resetMethod; // the reset property method
|
||
|
EventDescriptor realChangedEvent; // <propertyname>Changed event handler on object
|
||
|
EventDescriptor realIPropChangedEvent; // INotifyPropertyChanged.PropertyChanged event handler on object
|
||
|
Type receiverType; // Only set if we are an extender
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// The main constructor for ReflectPropertyDescriptors.
|
||
|
/// </devdoc>
|
||
|
public ReflectPropertyDescriptor(Type componentClass, string name, Type type,
|
||
|
Attribute[] attributes)
|
||
|
: base(name, attributes) {
|
||
|
|
||
|
Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "Creating ReflectPropertyDescriptor for " + componentClass.FullName + "." + name);
|
||
|
|
||
|
try {
|
||
|
if (type == null) {
|
||
|
Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "type == null, name == " + name);
|
||
|
throw new ArgumentException(SR.GetString(SR.ErrorInvalidPropertyType, name));
|
||
|
}
|
||
|
if (componentClass == null) {
|
||
|
Debug.WriteLineIf(PropDescCreateSwitch.TraceVerbose, "componentClass == null, name == " + name);
|
||
|
throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
|
||
|
}
|
||
|
this.type = type;
|
||
|
this.componentClass = componentClass;
|
||
|
}
|
||
|
catch (Exception t) {
|
||
|
Debug.Fail("Property '" + name + "' on component " + componentClass.FullName + " failed to init.");
|
||
|
Debug.Fail(t.ToString());
|
||
|
throw t;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// A constructor for ReflectPropertyDescriptors that have no attributes.
|
||
|
/// </devdoc>
|
||
|
public ReflectPropertyDescriptor(Type componentClass, string name, Type type, PropertyInfo propInfo, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs) {
|
||
|
this.propInfo = propInfo;
|
||
|
this.getMethod = getMethod;
|
||
|
this.setMethod = setMethod;
|
||
|
if (getMethod != null && propInfo != null && setMethod == null )
|
||
|
state[BitGetQueried | BitSetOnDemand] = true;
|
||
|
else
|
||
|
state[BitGetQueried | BitSetQueried] = true;
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// A constructor for ReflectPropertyDescriptors that creates an extender property.
|
||
|
/// </devdoc>
|
||
|
public ReflectPropertyDescriptor(Type componentClass, string name, Type type, Type receiverType, MethodInfo getMethod, MethodInfo setMethod, Attribute[] attrs) : this(componentClass, name, type, attrs) {
|
||
|
this.receiverType = receiverType;
|
||
|
this.getMethod = getMethod;
|
||
|
this.setMethod = setMethod;
|
||
|
state[BitGetQueried | BitSetQueried] = true;
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// This constructor takes an existing ReflectPropertyDescriptor and modifies it by merging in the
|
||
|
/// passed-in attributes.
|
||
|
/// </devdoc>
|
||
|
public ReflectPropertyDescriptor(Type componentClass, PropertyDescriptor oldReflectPropertyDescriptor, Attribute[] attributes)
|
||
|
: base(oldReflectPropertyDescriptor, attributes) {
|
||
|
|
||
|
this.componentClass = componentClass;
|
||
|
this.type = oldReflectPropertyDescriptor.PropertyType;
|
||
|
|
||
|
if (componentClass == null) {
|
||
|
throw new ArgumentException(SR.GetString(SR.InvalidNullArgument, "componentClass"));
|
||
|
}
|
||
|
|
||
|
// If the classes are the same, we can potentially optimize the method fetch because
|
||
|
// the old property descriptor may already have it.
|
||
|
//
|
||
|
ReflectPropertyDescriptor oldProp = oldReflectPropertyDescriptor as ReflectPropertyDescriptor;
|
||
|
if (oldProp != null) {
|
||
|
if (oldProp.ComponentType == componentClass) {
|
||
|
propInfo = oldProp.propInfo;
|
||
|
getMethod = oldProp.getMethod;
|
||
|
setMethod = oldProp.setMethod;
|
||
|
shouldSerializeMethod = oldProp.shouldSerializeMethod;
|
||
|
resetMethod = oldProp.resetMethod;
|
||
|
defaultValue = oldProp.defaultValue;
|
||
|
ambientValue = oldProp.ambientValue;
|
||
|
state = oldProp.state;
|
||
|
}
|
||
|
|
||
|
// Now we must figure out what to do with our default value. First, check to see
|
||
|
// if the caller has provided an new default value attribute. If so, use it. Otherwise,
|
||
|
// just let it be and it will be picked up on demand.
|
||
|
//
|
||
|
if (attributes != null) {
|
||
|
foreach(Attribute a in attributes) {
|
||
|
DefaultValueAttribute dva = a as DefaultValueAttribute;
|
||
|
|
||
|
if (dva != null) {
|
||
|
defaultValue = dva.Value;
|
||
|
// Default values for enums are often stored as their underlying integer type:
|
||
|
if (defaultValue != null && PropertyType.IsEnum && PropertyType.GetEnumUnderlyingType() == defaultValue.GetType()) {
|
||
|
defaultValue = Enum.ToObject(PropertyType, defaultValue);
|
||
|
}
|
||
|
|
||
|
state[BitDefaultValueQueried] = true;
|
||
|
}
|
||
|
else {
|
||
|
AmbientValueAttribute ava = a as AmbientValueAttribute;
|
||
|
if (ava != null) {
|
||
|
ambientValue = ava.Value;
|
||
|
state[BitAmbientValueQueried] = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#if DEBUG
|
||
|
else if (oldReflectPropertyDescriptor is DebugReflectPropertyDescriptor)
|
||
|
{
|
||
|
DebugReflectPropertyDescriptor oldProp1 = (DebugReflectPropertyDescriptor)oldReflectPropertyDescriptor;
|
||
|
|
||
|
if (oldProp1.ComponentType == componentClass) {
|
||
|
propInfo = oldProp1.propInfo;
|
||
|
getMethod = oldProp1.getMethod;
|
||
|
setMethod = oldProp1.setMethod;
|
||
|
shouldSerializeMethod = oldProp1.shouldSerializeMethod;
|
||
|
resetMethod = oldProp1.resetMethod;
|
||
|
defaultValue = oldProp1.defaultValue;
|
||
|
ambientValue = oldProp1.ambientValue;
|
||
|
state = oldProp1.state;
|
||
|
}
|
||
|
|
||
|
// Now we must figure out what to do with our default value. First, check to see
|
||
|
// if the caller has provided an new default value attribute. If so, use it. Otherwise,
|
||
|
// just let it be and it will be picked up on demand.
|
||
|
//
|
||
|
if (attributes != null) {
|
||
|
foreach(Attribute a in attributes) {
|
||
|
if (a is DefaultValueAttribute) {
|
||
|
defaultValue = ((DefaultValueAttribute)a).Value;
|
||
|
state[BitDefaultValueQueried] = true;
|
||
|
}
|
||
|
else if (a is AmbientValueAttribute) {
|
||
|
ambientValue = ((AmbientValueAttribute)a).Value;
|
||
|
state[BitAmbientValueQueried] = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Retrieves the ambient value for this property.
|
||
|
/// </devdoc>
|
||
|
private object AmbientValue {
|
||
|
get {
|
||
|
if (!state[BitAmbientValueQueried]) {
|
||
|
state[BitAmbientValueQueried] = true;
|
||
|
Attribute a = Attributes[typeof(AmbientValueAttribute)];
|
||
|
if (a != null) {
|
||
|
ambientValue = ((AmbientValueAttribute)a).Value;
|
||
|
}
|
||
|
else {
|
||
|
ambientValue = noValue;
|
||
|
}
|
||
|
}
|
||
|
return ambientValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// The EventDescriptor for the "{propertyname}Changed" event on the component, or null if there isn't one for this property.
|
||
|
/// </devdoc>
|
||
|
private EventDescriptor ChangedEventValue {
|
||
|
get {
|
||
|
if (!state[BitChangedQueried]) {
|
||
|
state[BitChangedQueried] = true;
|
||
|
realChangedEvent = TypeDescriptor.GetEvents(ComponentType)[string.Format(CultureInfo.InvariantCulture, "{0}Changed", Name)];
|
||
|
}
|
||
|
|
||
|
return realChangedEvent;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
set {
|
||
|
realChangedEvent = value;
|
||
|
state[BitChangedQueried] = true;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// The EventDescriptor for the INotifyPropertyChanged.PropertyChanged event on the component, or null if there isn't one for this property.
|
||
|
/// </devdoc>
|
||
|
private EventDescriptor IPropChangedEventValue {
|
||
|
get {
|
||
|
if (!state[BitIPropChangedQueried]) {
|
||
|
state[BitIPropChangedQueried] = true;
|
||
|
|
||
|
if (typeof(INotifyPropertyChanged).IsAssignableFrom(ComponentType)) {
|
||
|
realIPropChangedEvent = TypeDescriptor.GetEvents(typeof(INotifyPropertyChanged))["PropertyChanged"];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return realIPropChangedEvent;
|
||
|
}
|
||
|
set {
|
||
|
realIPropChangedEvent = value;
|
||
|
state[BitIPropChangedQueried] = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Retrieves the type of the component this PropertyDescriptor is bound to.
|
||
|
/// </devdoc>
|
||
|
public override Type ComponentType {
|
||
|
get {
|
||
|
return componentClass;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Retrieves the default value for this property.
|
||
|
/// </devdoc>
|
||
|
private object DefaultValue {
|
||
|
get {
|
||
|
if (!state[BitDefaultValueQueried]) {
|
||
|
state[BitDefaultValueQueried] = true;
|
||
|
Attribute a = Attributes[typeof(DefaultValueAttribute)];
|
||
|
if (a != null) {
|
||
|
defaultValue = ((DefaultValueAttribute)a).Value;
|
||
|
// Default values for enums are often stored as their underlying integer type:
|
||
|
if (defaultValue != null && PropertyType.IsEnum && PropertyType.GetEnumUnderlyingType() == defaultValue.GetType()) {
|
||
|
defaultValue = Enum.ToObject(PropertyType, defaultValue);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
defaultValue = noValue;
|
||
|
}
|
||
|
}
|
||
|
return defaultValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// The GetMethod for this property
|
||
|
/// </devdoc>
|
||
|
private MethodInfo GetMethodValue {
|
||
|
get {
|
||
|
if (!state[BitGetQueried]) {
|
||
|
state[BitGetQueried] = true;
|
||
|
|
||
|
if (receiverType == null) {
|
||
|
if (propInfo == null) {
|
||
|
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
|
||
|
propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
|
||
|
}
|
||
|
if (propInfo != null) {
|
||
|
getMethod = propInfo.GetGetMethod(true);
|
||
|
}
|
||
|
if (getMethod == null) {
|
||
|
throw new InvalidOperationException(SR.GetString(SR.ErrorMissingPropertyAccessors, componentClass.FullName + "." + Name));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
getMethod = FindMethod(componentClass, "Get" + Name, new Type[] { receiverType }, type);
|
||
|
if (getMethod == null) {
|
||
|
throw new ArgumentException(SR.GetString(SR.ErrorMissingPropertyAccessors, Name));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return getMethod;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
set {
|
||
|
state[BitGetQueried] = true;
|
||
|
getMethod = value;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Determines if this property is an extender property.
|
||
|
/// </devdoc>
|
||
|
private bool IsExtender {
|
||
|
get {
|
||
|
return (receiverType != null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Indicates whether this property is read only.
|
||
|
/// </devdoc>
|
||
|
public override bool IsReadOnly {
|
||
|
get {
|
||
|
return SetMethodValue == null || ((ReadOnlyAttribute)Attributes[typeof(ReadOnlyAttribute)]).IsReadOnly;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Retrieves the type of the property.
|
||
|
/// </devdoc>
|
||
|
public override Type PropertyType {
|
||
|
get {
|
||
|
return type;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Access to the reset method, if one exists for this property.
|
||
|
/// </devdoc>
|
||
|
private MethodInfo ResetMethodValue {
|
||
|
get {
|
||
|
if (!state[BitResetQueried]) {
|
||
|
state[BitResetQueried] = true;
|
||
|
|
||
|
Type[] args;
|
||
|
|
||
|
if (receiverType == null) {
|
||
|
args = argsNone;
|
||
|
}
|
||
|
else {
|
||
|
args = new Type[] {receiverType};
|
||
|
}
|
||
|
#if FEATURE_MONO_CAS
|
||
|
IntSecurity.FullReflection.Assert();
|
||
|
try {
|
||
|
#endif
|
||
|
resetMethod = FindMethod(componentClass, "Reset" + Name, args, typeof(void), /* publicOnly= */ false);
|
||
|
#if FEATURE_MONO_CAS
|
||
|
}
|
||
|
finally {
|
||
|
CodeAccessPermission.RevertAssert();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
return resetMethod;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
set {
|
||
|
state[BitResetQueried] = true;
|
||
|
resetMethod = value;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Accessor for the set method
|
||
|
/// </devdoc>
|
||
|
private MethodInfo SetMethodValue {
|
||
|
get {
|
||
|
if (!state[BitSetQueried] && state[BitSetOnDemand])
|
||
|
{
|
||
|
state[BitSetQueried] = true;
|
||
|
|
||
|
BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance;
|
||
|
string name = propInfo.Name;
|
||
|
|
||
|
if (setMethod == null)
|
||
|
{
|
||
|
for (Type t = ComponentType.BaseType; t != null && t != typeof(object); t = t.BaseType)
|
||
|
{
|
||
|
if (t == null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
PropertyInfo p = t.GetProperty(name, bindingFlags, null, PropertyType, new Type[0], null);
|
||
|
if (p != null)
|
||
|
{
|
||
|
setMethod = p.GetSetMethod();
|
||
|
if (setMethod != null)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (!state[BitSetQueried]) {
|
||
|
state[BitSetQueried] = true;
|
||
|
|
||
|
if (receiverType == null) {
|
||
|
if (propInfo == null) {
|
||
|
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty;
|
||
|
propInfo = componentClass.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
|
||
|
}
|
||
|
if (propInfo != null) {
|
||
|
setMethod = propInfo.GetSetMethod(true);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
setMethod = FindMethod(componentClass, "Set" + Name,
|
||
|
new Type[] { receiverType, type}, typeof(void));
|
||
|
}
|
||
|
}
|
||
|
return setMethod;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
set {
|
||
|
state[BitSetQueried] = true;
|
||
|
setMethod = value;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Accessor for the ShouldSerialize method.
|
||
|
/// </devdoc>
|
||
|
private MethodInfo ShouldSerializeMethodValue {
|
||
|
get {
|
||
|
if (!state[BitShouldSerializeQueried]) {
|
||
|
state[BitShouldSerializeQueried] = true;
|
||
|
|
||
|
Type[] args;
|
||
|
|
||
|
if (receiverType == null) {
|
||
|
args = argsNone;
|
||
|
}
|
||
|
else {
|
||
|
args = new Type[] {receiverType};
|
||
|
}
|
||
|
|
||
|
#if FEATURE_MONO_CAS
|
||
|
IntSecurity.FullReflection.Assert();
|
||
|
try {
|
||
|
#endif
|
||
|
shouldSerializeMethod = FindMethod(componentClass, "ShouldSerialize" + Name,
|
||
|
args, typeof(Boolean), /* publicOnly= */ false);
|
||
|
#if FEATURE_MONO_CAS
|
||
|
}
|
||
|
finally {
|
||
|
CodeAccessPermission.RevertAssert();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
return shouldSerializeMethod;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
set {
|
||
|
state[BitShouldSerializeQueried] = true;
|
||
|
shouldSerializeMethod = value;
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Allows interested objects to be notified when this property changes.
|
||
|
/// </devdoc>
|
||
|
public override void AddValueChanged(object component, EventHandler handler) {
|
||
|
if (component == null) throw new ArgumentNullException("component");
|
||
|
if (handler == null) throw new ArgumentNullException("handler");
|
||
|
|
||
|
// If there's an event called <propertyname>Changed, hook the caller's handler directly up to that on the component
|
||
|
EventDescriptor changedEvent = ChangedEventValue;
|
||
|
if (changedEvent != null && changedEvent.EventType.IsInstanceOfType(handler)) {
|
||
|
changedEvent.AddEventHandler(component, handler);
|
||
|
}
|
||
|
|
||
|
// Otherwise let the base class add the handler to its ValueChanged event for this component
|
||
|
else {
|
||
|
|
||
|
// Special case: If this will be the FIRST handler added for this component, and the component implements
|
||
|
// INotifyPropertyChanged, the property descriptor must START listening to the generic PropertyChanged event
|
||
|
if (GetValueChangedHandler(component) == null) {
|
||
|
EventDescriptor iPropChangedEvent = IPropChangedEventValue;
|
||
|
if (iPropChangedEvent != null) {
|
||
|
iPropChangedEvent.AddEventHandler(component, new PropertyChangedEventHandler(OnINotifyPropertyChanged));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
base.AddValueChanged(component, handler);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool ExtenderCanResetValue(IExtenderProvider provider, object component) {
|
||
|
if (DefaultValue != noValue) {
|
||
|
return !object.Equals(ExtenderGetValue(provider, component),defaultValue);
|
||
|
}
|
||
|
|
||
|
MethodInfo reset = ResetMethodValue;
|
||
|
if (reset != null) {
|
||
|
MethodInfo shouldSerialize = ShouldSerializeMethodValue;
|
||
|
if (shouldSerialize != null) {
|
||
|
try {
|
||
|
provider = (IExtenderProvider)GetInvocationTarget(componentClass, provider);
|
||
|
return (bool)shouldSerialize.Invoke(provider, new object[] { component});
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
internal Type ExtenderGetReceiverType() {
|
||
|
return receiverType;
|
||
|
}
|
||
|
|
||
|
internal Type ExtenderGetType(IExtenderProvider provider) {
|
||
|
return PropertyType;
|
||
|
}
|
||
|
|
||
|
internal object ExtenderGetValue(IExtenderProvider provider, object component) {
|
||
|
if (provider != null) {
|
||
|
provider = (IExtenderProvider)GetInvocationTarget(componentClass, provider);
|
||
|
return GetMethodValue.Invoke(provider, new object[] { component});
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
internal void ExtenderResetValue(IExtenderProvider provider, object component, PropertyDescriptor notifyDesc) {
|
||
|
if (DefaultValue != noValue) {
|
||
|
ExtenderSetValue(provider, component, DefaultValue, notifyDesc);
|
||
|
}
|
||
|
else if (AmbientValue != noValue) {
|
||
|
ExtenderSetValue(provider, component, AmbientValue, notifyDesc);
|
||
|
}
|
||
|
else if (ResetMethodValue != null) {
|
||
|
ISite site = GetSite(component);
|
||
|
IComponentChangeService changeService = null;
|
||
|
object oldValue = null;
|
||
|
object newValue;
|
||
|
|
||
|
// Announce that we are about to change this component
|
||
|
//
|
||
|
if (site != null) {
|
||
|
changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
|
||
|
Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
|
||
|
}
|
||
|
|
||
|
// Make sure that it is ok to send the onchange events
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
oldValue = ExtenderGetValue(provider, component);
|
||
|
try {
|
||
|
changeService.OnComponentChanging(component, notifyDesc);
|
||
|
}
|
||
|
catch (CheckoutException coEx) {
|
||
|
if (coEx == CheckoutException.Canceled) {
|
||
|
return;
|
||
|
}
|
||
|
throw coEx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
provider = (IExtenderProvider)GetInvocationTarget(componentClass, provider);
|
||
|
if (ResetMethodValue != null) {
|
||
|
ResetMethodValue.Invoke(provider, new object[] { component});
|
||
|
|
||
|
// Now notify the change service that the change was successful.
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
newValue = ExtenderGetValue(provider, component);
|
||
|
changeService.OnComponentChanged(component, notifyDesc, oldValue, newValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void ExtenderSetValue(IExtenderProvider provider, object component, object value, PropertyDescriptor notifyDesc) {
|
||
|
if (provider != null) {
|
||
|
|
||
|
ISite site = GetSite(component);
|
||
|
IComponentChangeService changeService = null;
|
||
|
object oldValue = null;
|
||
|
|
||
|
// Announce that we are about to change this component
|
||
|
//
|
||
|
if (site != null) {
|
||
|
changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
|
||
|
Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
|
||
|
}
|
||
|
|
||
|
// Make sure that it is ok to send the onchange events
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
oldValue = ExtenderGetValue(provider, component);
|
||
|
try {
|
||
|
changeService.OnComponentChanging(component, notifyDesc);
|
||
|
}
|
||
|
catch (CheckoutException coEx) {
|
||
|
if (coEx == CheckoutException.Canceled) {
|
||
|
return;
|
||
|
}
|
||
|
throw coEx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
provider = (IExtenderProvider)GetInvocationTarget(componentClass, provider);
|
||
|
|
||
|
if (SetMethodValue != null) {
|
||
|
SetMethodValue.Invoke(provider, new object[] { component, value});
|
||
|
|
||
|
// Now notify the change service that the change was successful.
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
changeService.OnComponentChanged(component, notifyDesc, oldValue, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal bool ExtenderShouldSerializeValue(IExtenderProvider provider, object component) {
|
||
|
|
||
|
|
||
|
provider = (IExtenderProvider)GetInvocationTarget(componentClass, provider);
|
||
|
|
||
|
if (IsReadOnly) {
|
||
|
if (ShouldSerializeMethodValue != null) {
|
||
|
try {
|
||
|
return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
|
||
|
}
|
||
|
else if (DefaultValue == noValue) {
|
||
|
if (ShouldSerializeMethodValue != null) {
|
||
|
try {
|
||
|
return (bool)ShouldSerializeMethodValue.Invoke(provider, new object[] {component});
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return !object.Equals(DefaultValue, ExtenderGetValue(provider, component));
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Indicates whether reset will change the value of the component. If there
|
||
|
/// is a DefaultValueAttribute, then this will return true if getValue returns
|
||
|
/// something different than the default value. If there is a reset method and
|
||
|
/// a ShouldSerialize method, this will return what ShouldSerialize returns.
|
||
|
/// If there is just a reset method, this always returns true. If none of these
|
||
|
/// cases apply, this returns false.
|
||
|
/// </devdoc>
|
||
|
public override bool CanResetValue(object component) {
|
||
|
if (IsExtender || IsReadOnly) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (DefaultValue != noValue) {
|
||
|
return !object.Equals(GetValue(component),DefaultValue);
|
||
|
}
|
||
|
|
||
|
if (ResetMethodValue != null) {
|
||
|
if (ShouldSerializeMethodValue != null) {
|
||
|
component = GetInvocationTarget(componentClass, component);
|
||
|
try {
|
||
|
return (bool)ShouldSerializeMethodValue.Invoke(component, null);
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (AmbientValue != noValue) {
|
||
|
return ShouldSerializeValue(component);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
protected override void FillAttributes(IList attributes) {
|
||
|
Debug.Assert(componentClass != null, "Must have a component class for FillAttributes");
|
||
|
|
||
|
//
|
||
|
// The order that we fill in attributes is critical. The list of attributes will be
|
||
|
// filtered so that matching attributes at the end of the list replace earlier matches
|
||
|
// (last one in wins). Therefore, the four categories of attributes we add must be
|
||
|
// added as follows:
|
||
|
//
|
||
|
// 1. Attributes of the property type. These are the lowest level and should be
|
||
|
// overwritten by any newer attributes.
|
||
|
//
|
||
|
// 2. Attributes obtained from any SpecificTypeAttribute. These supercede attributes
|
||
|
// for the property type.
|
||
|
//
|
||
|
// 3. Attributes of the property itself, from base class to most derived. This way
|
||
|
// derived class attributes replace base class attributes.
|
||
|
//
|
||
|
// 4. Attributes from our base MemberDescriptor. While this seems opposite of what
|
||
|
// we want, MemberDescriptor only has attributes if someone passed in a new
|
||
|
// set in the constructor. Therefore, these attributes always
|
||
|
// supercede existing values.
|
||
|
//
|
||
|
|
||
|
|
||
|
// We need to include attributes from the type of the property.
|
||
|
//
|
||
|
foreach (Attribute typeAttr in TypeDescriptor.GetAttributes(PropertyType)) {
|
||
|
attributes.Add(typeAttr);
|
||
|
}
|
||
|
|
||
|
// NOTE : Must look at method OR property, to handle the case of Extender properties...
|
||
|
//
|
||
|
// Note : Because we are using BindingFlags.DeclaredOnly it is more effcient to re-aquire
|
||
|
// : the property info, rather than use the one we have cached. The one we have cached
|
||
|
// : may ave come from a base class, meaning we will request custom metadata for this
|
||
|
// : class twice.
|
||
|
|
||
|
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly;
|
||
|
Type currentReflectType = componentClass;
|
||
|
int depth = 0;
|
||
|
|
||
|
// First, calculate the depth of the object hierarchy. We do this so we can do a single
|
||
|
// object create for an array of attributes.
|
||
|
//
|
||
|
while(currentReflectType != null && currentReflectType != typeof(object)) {
|
||
|
depth++;
|
||
|
currentReflectType = currentReflectType.BaseType;
|
||
|
}
|
||
|
|
||
|
// Now build up an array in reverse order
|
||
|
//
|
||
|
if (depth > 0) {
|
||
|
currentReflectType = componentClass;
|
||
|
Attribute[][] attributeStack = new Attribute[depth][];
|
||
|
|
||
|
while(currentReflectType != null && currentReflectType != typeof(object)) {
|
||
|
|
||
|
MemberInfo memberInfo = null;
|
||
|
|
||
|
// Fill in our member info so we can get at the custom attributes.
|
||
|
//
|
||
|
if (IsExtender) {
|
||
|
//receiverType is used to avoid ambitiousness when there are overloads for the get method.
|
||
|
memberInfo = currentReflectType.GetMethod("Get" + Name, bindingFlags, null, new Type[] { receiverType }, null);
|
||
|
}
|
||
|
else {
|
||
|
memberInfo = currentReflectType.GetProperty(Name, bindingFlags, null, PropertyType, new Type[0], new ParameterModifier[0]);
|
||
|
}
|
||
|
|
||
|
// Get custom attributes for the member info.
|
||
|
//
|
||
|
if (memberInfo != null) {
|
||
|
attributeStack[--depth] = ReflectTypeDescriptionProvider.ReflectGetAttributes(memberInfo);
|
||
|
}
|
||
|
|
||
|
// Ready for the next loop iteration.
|
||
|
//
|
||
|
currentReflectType = currentReflectType.BaseType;
|
||
|
}
|
||
|
|
||
|
// Look in the attribute stack for AttributeProviders
|
||
|
//
|
||
|
foreach(Attribute[] attributeArray in attributeStack)
|
||
|
{
|
||
|
if (attributeArray != null)
|
||
|
{
|
||
|
foreach(Attribute attr in attributeArray) {
|
||
|
AttributeProviderAttribute sta = attr as AttributeProviderAttribute;
|
||
|
if (sta != null)
|
||
|
{
|
||
|
Type specificType = Type.GetType(sta.TypeName);
|
||
|
|
||
|
if (specificType != null)
|
||
|
{
|
||
|
Attribute[] stAttrs = null;
|
||
|
|
||
|
if (!String.IsNullOrEmpty(sta.PropertyName)) {
|
||
|
MemberInfo[] milist = specificType.GetMember(sta.PropertyName);
|
||
|
if (milist.Length > 0 && milist[0] != null) {
|
||
|
stAttrs = ReflectTypeDescriptionProvider.ReflectGetAttributes(milist[0]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
stAttrs = ReflectTypeDescriptionProvider.ReflectGetAttributes(specificType);
|
||
|
}
|
||
|
if (stAttrs != null)
|
||
|
{
|
||
|
foreach(Attribute stAttr in stAttrs)
|
||
|
{
|
||
|
attributes.Add(stAttr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now trawl the attribute stack so that we add attributes
|
||
|
// from base class to most derived.
|
||
|
//
|
||
|
foreach(Attribute[] attributeArray in attributeStack) {
|
||
|
if (attributeArray != null)
|
||
|
{
|
||
|
foreach(Attribute attr in attributeArray) {
|
||
|
attributes.Add(attr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Include the base attributes. These override all attributes on the actual
|
||
|
// property, so we want to add them last.
|
||
|
//
|
||
|
base.FillAttributes(attributes);
|
||
|
|
||
|
// Finally, override any form of ReadOnlyAttribute.
|
||
|
//
|
||
|
if (SetMethodValue == null) {
|
||
|
attributes.Add(ReadOnlyAttribute.Yes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Retrieves the current value of the property on component,
|
||
|
/// invoking the getXXX method. An exception in the getXXX
|
||
|
/// method will pass through.
|
||
|
/// </devdoc>
|
||
|
public override object GetValue(object component) {
|
||
|
#if DEBUG
|
||
|
if (PropDescUsageSwitch.TraceVerbose) {
|
||
|
string compName = "(null)";
|
||
|
if (component != null)
|
||
|
compName = component.ToString();
|
||
|
|
||
|
Debug.WriteLine("[" + Name + "]: GetValue(" + compName + ")");
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (IsExtender) {
|
||
|
Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
Debug.Assert(component != null, "GetValue must be given a component");
|
||
|
|
||
|
if (component != null) {
|
||
|
component = GetInvocationTarget(componentClass, component);
|
||
|
|
||
|
|
||
|
try {
|
||
|
return SecurityUtils.MethodInfoInvoke(GetMethodValue, component, null);
|
||
|
}
|
||
|
catch (Exception t) {
|
||
|
|
||
|
string name = null;
|
||
|
IComponent comp = component as IComponent;
|
||
|
if (comp != null) {
|
||
|
ISite site = comp.Site;
|
||
|
if (site != null && site.Name != null) {
|
||
|
name = site.Name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (name == null) {
|
||
|
name = component.GetType().FullName;
|
||
|
}
|
||
|
|
||
|
if (t is TargetInvocationException) {
|
||
|
t = t.InnerException;
|
||
|
}
|
||
|
|
||
|
string message = t.Message;
|
||
|
if (message == null) {
|
||
|
message = t.GetType().Name;
|
||
|
}
|
||
|
|
||
|
throw new TargetInvocationException(SR.GetString(SR.ErrorPropertyAccessorException, Name, name, message), t);
|
||
|
}
|
||
|
}
|
||
|
Debug.WriteLineIf(PropDescUsageSwitch.TraceVerbose, "[" + Name + "]: ---> returning: null");
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Handles INotifyPropertyChanged.PropertyChange events from components.
|
||
|
/// If event pertains to this property, issue a ValueChanged event.
|
||
|
/// </devdoc>
|
||
|
/// </internalonly>
|
||
|
internal void OnINotifyPropertyChanged(object component, PropertyChangedEventArgs e) {
|
||
|
if (String.IsNullOrEmpty(e.PropertyName) ||
|
||
|
String.Compare(e.PropertyName, Name, true, System.Globalization.CultureInfo.InvariantCulture) == 0) {
|
||
|
OnValueChanged(component, e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// This should be called by your property descriptor implementation
|
||
|
/// when the property value has changed.
|
||
|
/// </devdoc>
|
||
|
protected override void OnValueChanged(object component, EventArgs e) {
|
||
|
if (state[BitChangedQueried] && realChangedEvent == null) {
|
||
|
base.OnValueChanged(component, e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Allows interested objects to be notified when this property changes.
|
||
|
/// </devdoc>
|
||
|
public override void RemoveValueChanged(object component, EventHandler handler) {
|
||
|
if (component == null) throw new ArgumentNullException("component");
|
||
|
if (handler == null) throw new ArgumentNullException("handler");
|
||
|
|
||
|
// If there's an event called <propertyname>Changed, we hooked the caller's
|
||
|
// handler directly up to that on the component, so remove it now.
|
||
|
EventDescriptor changedEvent = ChangedEventValue;
|
||
|
if (changedEvent != null && changedEvent.EventType.IsInstanceOfType(handler)) {
|
||
|
changedEvent.RemoveEventHandler(component, handler);
|
||
|
}
|
||
|
|
||
|
// Otherwise the base class added the handler to its ValueChanged
|
||
|
// event for this component, so let the base class remove it now.
|
||
|
else {
|
||
|
base.RemoveValueChanged(component, handler);
|
||
|
|
||
|
// Special case: If that was the LAST handler removed for this component, and the component implements
|
||
|
// INotifyPropertyChanged, the property descriptor must STOP listening to the generic PropertyChanged event
|
||
|
if (GetValueChangedHandler(component) == null) {
|
||
|
EventDescriptor iPropChangedEvent = IPropChangedEventValue;
|
||
|
if (iPropChangedEvent != null) {
|
||
|
iPropChangedEvent.RemoveEventHandler(component, new PropertyChangedEventHandler(OnINotifyPropertyChanged));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Will reset the default value for this property on the component. If
|
||
|
/// there was a default value passed in as a DefaultValueAttribute, that
|
||
|
/// value will be set as the value of the property on the component. If
|
||
|
/// there was no default value passed in, a ResetXXX method will be looked
|
||
|
/// for. If one is found, it will be invoked. If one is not found, this
|
||
|
/// is a nop.
|
||
|
/// </devdoc>
|
||
|
public override void ResetValue(object component) {
|
||
|
object invokee = GetInvocationTarget(componentClass, component);
|
||
|
|
||
|
if (DefaultValue != noValue) {
|
||
|
SetValue(component, DefaultValue);
|
||
|
}
|
||
|
else if (AmbientValue != noValue) {
|
||
|
SetValue(component, AmbientValue);
|
||
|
}
|
||
|
else if (ResetMethodValue != null) {
|
||
|
ISite site = GetSite(component);
|
||
|
IComponentChangeService changeService = null;
|
||
|
object oldValue = null;
|
||
|
object newValue;
|
||
|
|
||
|
// Announce that we are about to change this component
|
||
|
//
|
||
|
if (site != null) {
|
||
|
changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
|
||
|
Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
|
||
|
}
|
||
|
|
||
|
// Make sure that it is ok to send the onchange events
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
// invokee might be a type from mscorlib or system, GetMethodValue might return a NonPublic method
|
||
|
oldValue = SecurityUtils.MethodInfoInvoke(GetMethodValue, invokee, (object[])null);
|
||
|
try {
|
||
|
changeService.OnComponentChanging(component, this);
|
||
|
}
|
||
|
catch (CheckoutException coEx) {
|
||
|
if (coEx == CheckoutException.Canceled) {
|
||
|
return;
|
||
|
}
|
||
|
throw coEx;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if (ResetMethodValue != null) {
|
||
|
SecurityUtils.MethodInfoInvoke(ResetMethodValue, invokee, (object[])null);
|
||
|
|
||
|
// Now notify the change service that the change was successful.
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
newValue = SecurityUtils.MethodInfoInvoke(GetMethodValue, invokee, (object[])null);
|
||
|
changeService.OnComponentChanged(component, this, oldValue, newValue);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// This will set value to be the new value of this property on the
|
||
|
/// component by invoking the setXXX method on the component. If the
|
||
|
/// value specified is invalid, the component should throw an exception
|
||
|
/// which will be passed up. The component designer should design the
|
||
|
/// property so that getXXX following a setXXX should return the value
|
||
|
/// passed in if no exception was thrown in the setXXX call.
|
||
|
/// </devdoc>
|
||
|
public override void SetValue(object component, object value) {
|
||
|
#if DEBUG
|
||
|
if (PropDescUsageSwitch.TraceVerbose) {
|
||
|
string compName = "(null)";
|
||
|
string valName = "(null)";
|
||
|
|
||
|
if (component != null)
|
||
|
compName = component.ToString();
|
||
|
if (value != null)
|
||
|
valName = value.ToString();
|
||
|
|
||
|
Debug.WriteLine("[" + Name + "]: SetValue(" + compName + ", " + valName + ")");
|
||
|
}
|
||
|
#endif
|
||
|
if (component != null) {
|
||
|
ISite site = GetSite(component);
|
||
|
IComponentChangeService changeService = null;
|
||
|
object oldValue = null;
|
||
|
|
||
|
object invokee = GetInvocationTarget(componentClass, component);
|
||
|
|
||
|
if (!IsReadOnly) {
|
||
|
|
||
|
// Announce that we are about to change this component
|
||
|
//
|
||
|
if (site != null) {
|
||
|
changeService = (IComponentChangeService)site.GetService(typeof(IComponentChangeService));
|
||
|
Debug.Assert(!CompModSwitches.CommonDesignerServices.Enabled || changeService != null, "IComponentChangeService not found");
|
||
|
}
|
||
|
|
||
|
|
||
|
// Make sure that it is ok to send the onchange events
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
oldValue = SecurityUtils.MethodInfoInvoke(GetMethodValue, invokee, (object[])null);
|
||
|
try {
|
||
|
changeService.OnComponentChanging(component, this);
|
||
|
}
|
||
|
catch (CheckoutException coEx) {
|
||
|
if (coEx == CheckoutException.Canceled) {
|
||
|
return;
|
||
|
}
|
||
|
throw coEx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
try {
|
||
|
try {
|
||
|
SecurityUtils.MethodInfoInvoke(SetMethodValue, invokee, new object[] { value });
|
||
|
OnValueChanged(invokee, EventArgs.Empty);
|
||
|
}
|
||
|
catch (Exception t) {
|
||
|
// Give ourselves a chance to unwind properly before rethrowing the exception.
|
||
|
//
|
||
|
value = oldValue;
|
||
|
|
||
|
// If there was a problem setting the controls property then we get:
|
||
|
// ArgumentException (from properties set method)
|
||
|
// ==> Becomes inner exception of TargetInvocationException
|
||
|
// ==> caught here
|
||
|
|
||
|
if (t is TargetInvocationException && t.InnerException != null) {
|
||
|
// Propagate the original exception up
|
||
|
throw t.InnerException;
|
||
|
}
|
||
|
else {
|
||
|
throw t;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
// Now notify the change service that the change was successful.
|
||
|
//
|
||
|
if (changeService != null) {
|
||
|
changeService.OnComponentChanged(component, this, oldValue, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Indicates whether the value of this property needs to be persisted. In
|
||
|
/// other words, it indicates whether the state of the property is distinct
|
||
|
/// from when the component is first instantiated. If there is a default
|
||
|
/// value specified in this ReflectPropertyDescriptor, it will be compared against the
|
||
|
/// property's current value to determine this. If there is't, the
|
||
|
/// ShouldSerializeXXX method is looked for and invoked if found. If both
|
||
|
/// these routes fail, true will be returned.
|
||
|
///
|
||
|
/// If this returns false, a tool should not persist this property's value.
|
||
|
/// </devdoc>
|
||
|
public override bool ShouldSerializeValue(object component) {
|
||
|
|
||
|
component = GetInvocationTarget(componentClass, component);
|
||
|
|
||
|
if (IsReadOnly) {
|
||
|
if (ShouldSerializeMethodValue != null) {
|
||
|
try {
|
||
|
return (bool)ShouldSerializeMethodValue.Invoke(component, null);
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return Attributes.Contains(DesignerSerializationVisibilityAttribute.Content);
|
||
|
}
|
||
|
else if (DefaultValue == noValue) {
|
||
|
if (ShouldSerializeMethodValue != null) {
|
||
|
try {
|
||
|
return (bool)ShouldSerializeMethodValue.Invoke(component, null);
|
||
|
}
|
||
|
catch {}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return !object.Equals(DefaultValue, GetValue(component));
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// Indicates whether value change notifications for this property may originate from outside the property
|
||
|
/// descriptor, such as from the component itself (value=true), or whether notifications will only originate
|
||
|
/// from direct calls made to PropertyDescriptor.SetValue (value=false). For example, the component may
|
||
|
/// implement the INotifyPropertyChanged interface, or may have an explicit '{name}Changed' event for this property.
|
||
|
/// </devdoc>
|
||
|
public override bool SupportsChangeEvents {
|
||
|
get {
|
||
|
return IPropChangedEventValue != null || ChangedEventValue != null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
The following code has been removed to fix FXCOP violations. The code
|
||
|
is left here incase it needs to be resurrected in the future.
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// A constructor for ReflectPropertyDescriptors that have no attributes.
|
||
|
/// </devdoc>
|
||
|
public ReflectPropertyDescriptor(Type componentClass, string name, Type type) : this(componentClass, name, type, (Attribute[])null) {
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
}
|