let's imagine i have the following classes that i am not allowed to change:
public class BaseType
{
public UInt32 m_baseMember = 1;
public bool m_baseMemberBool = false;
}
public class ComposedType
{
public ComposedType()
{
m_baseData = new BaseType();
}
public UInt32 m_newMember = 2;
public BaseType m_baseData;
}
Now i want to edit those data by putting it in an PropertyGrid. I created two Wrapper classes like those ( http://msdn.microsoft.com/en-us/magazine/cc163816.aspx )
public class FieldsToPropertiesProxyTypeDescriptor : ICustomTypeDescriptor
{
private object _target;
// object to be described
public FieldsToPropertiesProxyTypeDescriptor(object target)
{
if (target == null)
throw new ArgumentNullException("target");
_target = target;
}
public object GetProxiedObject()
{
return _target;
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
return _target;
// properties belong to the target object
}
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
// Gets the attributes of the target object
return TypeDescriptor.GetAttributes(_target, true);
}
string ICustomTypeDescriptor.GetClassName()
{
// Gets the class name of the target object
return TypeDescriptor.GetClassName(_target, true);
}
string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(_target, true);
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(_target, true);
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(_target, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(_target, true);
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(_target, editorBaseType);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(_target, attributes);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents( _target );
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(null);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties( Attribute[] attributes)
{
bool filtering = (attributes != null && attributes.Length > 0);
PropertyDescriptorCollection props = new PropertyDescriptorCollection(null);
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(_target, attributes, true))
{
props.Add(prop);
}
foreach (FieldInfo field in _target.GetType().GetFields())
{
FieldPropertyDescriptor fieldDesc = new FieldPropertyDescriptor(field);
if (!filtering || fieldDesc.Attributes.Contains(attributes))
props.Add(fieldDesc);
}
return props;
}
}
public class FieldPropertyDescriptor : PropertyDescriptor
{
private FieldInfo _field;
public FieldPropertyDescriptor(FieldInfo field) : base(field.Name, (Attribute[])field.GetCustomAttributes(typeof(Attribute), true))
{
_field = field;
}
public FieldInfo Field
{
get { return _field; }
}
public override bool Equals(object obj)
{
FieldPropertyDescriptor other = obj as FieldPropertyDescriptor;
return other != null && other._field.Equals(_field);
}
public override int GetHashCode()
{
return _field.GetHashCode();
}
public override bool IsReadOnly
{
get { return false; }
}
public override AttributeCollection Attributes
{
get
{
if (_field.FieldType.IsClass || _field.FieldType.IsArray)
{
Attribute[] expandable = new Attribute[1];
expandable[0] = new ExpandableObjectAttribute();
return AttributeCollection.FromExisting(base.Attributes, expandable);
}
return base.Attributes;
}
}
public override void ResetValue(object component)
{
}
public override bool CanResetValue(object component)
{
return false;
}
public override bool ShouldSerializeValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return _field.DeclaringType; }
}
public override Type PropertyType
{
get { return _field.FieldType; }
}
public override object GetValue(object component)
{
if (component is FieldsToPropertiesProxyTypeDescriptor)
{
FieldsToPropertiesProxyTypeDescriptor proxy = (FieldsToPropertiesProxyTypeDescriptor)component;
return _field.GetValue(proxy.GetProxiedObject());
}
return _field.GetValue(component);
}
public override void SetValue(object component, object value)
{
if (component is FieldsToPropertiesProxyTypeDescriptor)
{
FieldsToPropertiesProxyTypeDescriptor proxy = (FieldsToPropertiesProxyTypeDescriptor)component;
_field.SetValue(proxy.GetProxiedObject(), value);
OnValueChanged(proxy.GetProxiedObject(), EventArgs.Empty);
return;
}
_field.SetValue(component, value);
OnValueChanged(component, EventArgs.Empty);
}
}
I can see and edit the 'm_newMember' in the PropertyGrid but i need to wrap the access to 'm_baseData' via FieldsToPropertiesProxyTypeDescriptor. How could i achieve this. Or is there a better way to wrap fields into Properties?
You can change attributes of a given class at runtime without changing that class. So you could write a custom TypeConverter and set it to your classes, something like this:
With the following TypeConverter (re-using your FieldDescriptor class):