Search code examples
c#propertygridtypeconverter

Provide string for int property in PropertyGrid


Let's say I have a class with a integer property which I want to show in a PropertyGrid. Now the PropertyGrid should not simply show the integer value, but the corresponding string value from a list and further a drop down list with possible values (also as strings) for that property.

I know I have to use a TypeConverter for this and I have done this for string properties in the past. But I can't figure out how this has to be done. As you can see from my code, I'm completely helpless:

class MyClassConverter : TypeConverter
{
    List<string> values = new List<string>(); 

    public MyClassConverter()
    {
        values.Add("Value1");
        values.Add("Value2");
        values.Add("Value3");
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        bool ret = true; //base.CanConvertFrom(context, sourceType);
        Debug.Print("CanConvertFrom: " + sourceType.ToString() + " " + ret.ToString());
        return ret;
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        bool ret = base.CanConvertTo(context, destinationType);
        Debug.Print("CanConvertTo: " + destinationType.ToString() + " " + ret.ToString());
        return ret;
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        Debug.Print("ConvertFrom: " + value.GetType().ToString());
        //return base.ConvertFrom(context, culture, value);
        for (int i = 0; i < values.Count; i++)
        {
            if (values[i] == value)
            {
                return i;
            }
        }
        return -1;
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        Debug.Print("ConvertTo: " + destinationType.ToString());
        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        Debug.Print("GetStandardValues");
        StandardValuesCollection collection = new StandardValuesCollection(values);
        return collection;
    }

    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }
}

Solution

  • You have to implement ConvertTo with an int type as input (and an implicit string type as output, since you're talking to the property grid).

    Also, if you want to support direct end user int input, you need also to implement ConvertFrom from an int as a string (like "2" for example).

    Here is a piece of code that seems to work:

    public class MyClassConverter : TypeConverter
    {
        private List<string> values = new List<string>();
    
        public MyClassConverter()
        {
            values.Add("Value1");
            values.Add("Value2");
            values.Add("Value3");
        }
    
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (value is int)
            {
                int index = (int)value;
                if (index >= 0 && index < values.Count)
                    return values[index];
    
                return values[0]; // error, go back to first
            }
            return value;
        }
    
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
    
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            string s = value as string;
            if (s != null)
            {
                int index = values.IndexOf(s);
                if (index >= 0)
                    return index;
    
                // support direct integer input & validate
                if (int.TryParse(s, out index) && index >= 0 && index < values.Count)
                    return index;
    
                return 0; // error, go back to first
            }
    
            return base.ConvertFrom(context, culture, value);
        }
    
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            return new StandardValuesCollection(values);
        }
    
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }
    }