Search code examples
c#winformstypeconverter

TypeConverter for property of Type object


I need to display an object correctly in the propertygrid. my class looks like this:

public class PropertyItem
{
    public PropertyDescription PropertyDescription { get; set; }

    [Description("the value"), Browsable(true)]
    public object Value { get; set; }

    public PropertyItem(PropertyDescription propertyDescription, object value)
    {
        PropertyDescription = propertyDescription;
        Value = value;
    }

    public override string ToString()
    {
        return this.PropertyDescription.Name + ": " + PropertyDescription.Type + ": " + Value;
    }
}

Value is of type object and this cannot be changed. The PropertyDescription has the type of the Value and this can be anything (string, int, bool...)

When I set the SelectedObject of my PropertyGrid, the Value is always disabled.

How would I write a TypeConverter to convert the object Value to the Type in the PropertyDescription?


Solution

  • Define a custom type converter for the property:

    [TypeConverter(typeof(PropertyValueConverter))]
    public object Value { get; set; }
    

    And implement it like this:

    public class PropertyValueConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            var propItem = context.Instance as PropertyItem;
            return propItem != null && TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).CanConvertFrom(context, sourceType)
                || base.CanConvertFrom(context, sourceType);
        }
    
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            var propItem = context.Instance as PropertyItem;
            if (propItem != null)
                return TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).ConvertFrom(context, culture, value);
            else
                return base.ConvertFrom(context, culture, value);
        }
    }
    

    This test code worked for me:

    var pi = new PropertyItem(new PropertyDescription { Type = typeof(int) }, 1);
    propertyGrid1.SelectedObject = pi;
    

    Update:

    To support dropdown list (eg. bool):

        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            var propItem = context.Instance as PropertyItem;
            if (propItem != null)
                return TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).GetStandardValues(context);
            else
                return base.GetStandardValues(context);
        }
    
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            var propItem = context.Instance as PropertyItem;
            if (propItem != null)
                return TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).GetStandardValuesSupported(context);
            else
                return base.GetStandardValuesSupported(context);
        }
    

    To support custom openable properties (eg. Point):

        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            var propItem = context.Instance as PropertyItem;
            if (propItem != null)
                return TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).GetProperties(context, value, attributes);
            else
                return base.GetProperties(context, value, attributes);
        }
    
        public override bool GetPropertiesSupported(ITypeDescriptorContext context)
        {
            var propItem = context.Instance as PropertyItem;
            if (propItem != null)
                return TypeDescriptor.GetConverter(propItem.PropertyDescription.Type).GetPropertiesSupported(context);
            return base.GetPropertiesSupported(context);
        }