If you utilise ICustomTypeConverter to add extra properties on an object, the PropertyGrid does not correctly use ICustomTypeConverter.GetPropertyOwner(). I believe that this is because in CreatePropertyItem() assumes SelectedObject is the correct instance, where it should be requesting the object instance using code similar to:
public object GetValueInstance(object sourceObject)
{
ICustomTypeDescriptor customTypeDescriptor = sourceObject as ICustomTypeDescriptor;
if (customTypeDescriptor != null)
sourceObject = customTypeDescriptor.GetPropertyOwner(PropertyDescriptor);
return sourceObject;
}
For example, if you have the following the property grid will generate an error: public class TestSubClass
{
public string ExtendedField { get; set; }
}
public class TestClass : ICustomTypeDescriptor
{
public TestClass()
{
}
public string Name { get; set; }
[Browsable(false)]
public TestSubClass SubInfo { get; set; }
#region ICustomTypeDescriptor implementation
#region Standard implementation
AttributeCollection ICustomTypeDescriptor.GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
string ICustomTypeDescriptor.GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
string ICustomTypeDescriptor.GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
TypeConverter ICustomTypeDescriptor.GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
EventDescriptor ICustomTypeDescriptor.GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty()
{
return TypeDescriptor.GetDefaultProperty(this, true);
}
object ICustomTypeDescriptor.GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
#endregion
#region Custom implmenetation
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)
{
return GetCombinedProperties(attributes);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return GetCombinedProperties(null);
}
PropertyDescriptorCollection GetCombinedProperties(Attribute[] attributes)
{
PropertyDescriptorCollection ourPropsCollection = TypeDescriptor.GetProperties(this, attributes, true);
List<PropertyDescriptor> ourProps = new List<PropertyDescriptor>();
foreach (PropertyDescriptor prop in ourPropsCollection)
ourProps.Add(prop);
if (SubInfo == null)
SubInfo = new TestSubClass();
if (SubInfo != null)
{
PropertyDescriptorCollection setProps = TypeDescriptor.GetProperties(SubInfo, attributes, true);
if (setProps != null)
{
foreach (PropertyDescriptor prop in setProps)
{
ourProps.Add(prop);
}
}
}
return new PropertyDescriptorCollection(ourProps.ToArray());
}
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
{
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this, true);
if (props.Contains(pd))
return this;
else
return SubInfo;
}
#endregion
#endregion ICustomTypeDescriptor implementation
}