2

I have a nullable property in my class and I want user to be able to create its instance using PropertyGrid. Which I did using ExpandableObjectConverter.

When instance is created it automatically appears in PropertyGrid with posibility to expand it and change its properties' values.

Still I need to type some string to create a new instance.

That is why I am wondering if it is possible to combine ExpandableObjectConverter with DropDownList. So user would be able to select one of the existing values.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
walruz
  • 1,135
  • 1
  • 13
  • 33
  • There was a way to create [custom editors](https://stackoverflow.com/q/1016239/1997232) for `PropertyGrid`. – Sinatr Dec 18 '18 at 12:05
  • @Sinatr - in my understanding - UITypeEditor provides a choise between DropDown and custom Form. But I would not be able to mix expandable layout with drop down, right? – walruz Dec 18 '18 at 12:10
  • You just need to set/associate that property with an enumerator. Define a `public enum MyPropertySettings (...)`, then, in the Property definition: `[Category("Category"), DefaultValue(MyPropertySettings.PropertyValue1)] public MyPropertySettings MyProperty { get; set; } = MyPropertySettings.PropertyValue1;`. When selected, that property value will be set using the standard DropDown control. – Jimi Dec 18 '18 at 12:28

1 Answers1

2

You need to create a new ExpandableObjectConverter, supporting standard values.

Example

As an example, lets say, xlass A has a property of type B and we like to let the user to choose some predefined values for B from a drop-down list in property grid.

After you select something from dropdown, the B will be initialized and you still can edit C:

enter image description here

Here is the definition for A and B:

public class A
{
    [TypeConverter(typeof(BConverter))]
    public B B { get; set; }
}
public class B : ICloneable
{
    [RefreshProperties(RefreshProperties.All)]
    public string C { get; set; }
    public object Clone()
    {
        return new B { C = this.C };
    }
    public override string ToString()
    {
        return C;
    }
}

Here is the custom ExpandableObjectConverter:

public class BConverter : ExpandableObjectConverter
{
    B[] values = new B[] { new B { C = "Something" }, new B { C = "Something else" } };
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
            return true;
        return base.CanConvertFrom(context, sourceType);
    }
    public override object ConvertFrom(ITypeDescriptorContext context, 
        System.Globalization.CultureInfo culture, object value)
    {
        var result = values.Where(x => $"{x}" == $"{value}").FirstOrDefault();
        if (result != null)
            return result.Clone();
        return base.ConvertFrom(context, culture, value);
    }
    public override bool GetStandardValuesSupported(ITypeDescriptorContext c)
    {
        return true;
    }
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext c)
    {
        return true;
    }
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext c)
    {
        return new StandardValuesCollection(values);
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398