You can refer to Marc Gravell's example here.
Data binding dynamic data
I had to adjust others' code to make dropdowns work, and I apologize if this is not a complete list.
Your custom class's GetConverter() method should just return TypeDescriptor.GetConverter(this, true).
If you are not aware, your custom class's dynamic properties won't work with DataGridView, because of how the DGV reads them. So my implementation here is limited to PropertyGrid. Trying to use DataGridView together with ICustomTypeDescriptor
Decide whether the PropertyGrid combobox should be editable. How do I add an editable combobox to a System.Windows.Forms.PropertyGrid?
// also necessary to make propertyInfo work
// this allows us to assign lists to propertyGrid dropdowns
[TypeConverter(typeof(PrebuiltListConverter))]
public class DecoratedDropdown { }
public class PrebuiltListConverter : StringConverter
{
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
CvarPropertyDescriptor descriptor = (CvarPropertyDescriptor)context.PropertyDescriptor;
return new StandardValuesCollection(descriptor.Options);
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) { return true; }
// credit Zlatko; return false in StringConverter subclass to make editable combobox
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) { return false; }
}
- Your custom PropertyDescriptor needs to keep a reference to your custom property (e.g. m_Property below). It also must override PropertyType to return a Type associated with A) the custom class's type when there's no dropdown, or B) your dropdown-decorated subclass of the StringConverter.
public override Type PropertyType { get { return m_Property.Type; } }
I use a Type property on my custom property class to make that decision:
public Type Type
{
get
{
if (IsDropDownEnabled)
return typeof(DecoratedDropdown);
else
return typeof(this);
}
}
- The PropertyDescriptor needs dynamic to return the List of optional values for that property, a list I store on my custom property class. I can't tell you if representing the optional values with a List works.
public ICollection Options { get { dynamic dObj = m_Property; return dObj.PossibleValues; } }
- Your custom class needs to have a full TypeDescriptor implementation.
public String GetClassName() { return TypeDescriptor.GetClassName(this, true); }
public AttributeCollection GetAttributes() { return TypeDescriptor.GetAttributes(this, true); }
public String GetComponentName() { return TypeDescriptor.GetComponentName(this, true); }
public TypeConverter GetConverter() { return TypeDescriptor.GetConverter(this, true); }
public EventDescriptor GetDefaultEvent() { return TypeDescriptor.GetDefaultEvent(this, true); }
public PropertyDescriptor GetDefaultProperty() { return TypeDescriptor.GetDefaultProperty(this, true); }
public object GetEditor(Type editorBaseType) { return TypeDescriptor.GetEditor(this, editorBaseType, true); }
public EventDescriptorCollection GetEvents(Attribute[] attributes) { return TypeDescriptor.GetEvents(this, attributes, true); }
public EventDescriptorCollection GetEvents() { return TypeDescriptor.GetEvents(this, true); }
// GetProperties(Attribute[] attributes) etc.
public PropertyDescriptorCollection GetProperties() { return TypeDescriptor.GetProperties(this, true); }
public object GetPropertyOwner(PropertyDescriptor pd) { return this; }
Let me know if I missed anything. I did this one fairly recently.