0

I have to create some dynamic properties in propertygrid based on some action. I am able to create dynamic properties following https://www.codeproject.com/Articles/9280/Add-Remove-Items-to-from-PropertyGrid-at-Runtime example. But I need to add a combobox in the propertygrid also. For that I have created a class derived from stringConverter. Like below:

 public class FormatStringConverter : StringConverter
{
    public override Boolean GetStandardValuesSupported(ITypeDescriptorContext context) { return true; }
    public override Boolean GetStandardValuesExclusive(ITypeDescriptorContext context) { return true; }
    public override TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        List<String> list = new List<String>();
        list.Add("DepartmentA");        
        list.Add("DepartmentB");                
        list.Add("DepartmentC");
        return new StandardValuesCollection(list);
    }
}

But In example's customClass's what should I return to show stringConverters values as combobox in propertygrid?

TypeConverter GetConverter()
{
   if(prop.Name == "department")
       //what to return here?
   else
       return TypeDescriptor.GetConverter(this, true);
}

If anyone solved it using other TypeConverters I will appriciate if it helps my cause.

Shakhawat95
  • 443
  • 1
  • 6
  • 19

1 Answers1

0

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.

  1. Your custom class's GetConverter() method should just return TypeDescriptor.GetConverter(this, true).

  2. 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

  3. 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; }
    }
  1. 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);
        }
    }
  1. 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; } }
  1. 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.

RBJ
  • 128
  • 6