Search code examples
c#.netwinformspropertygrid

Use a custom editor in a PropertyGrid for a type I cannot modify


In my application I have an object which's properties I want to edit using a PropertyGrid. For most of the properties this works fine. Now this object contains a property of type List<string>. When editing this property I get an error because string doesn't have a suitable constructor.

Basically this is the same situation as described in this question.

Unfortunately I can't use the answer from there because I can't modify the code of my object, so applying the Editor attribute to the property is not an option. Is there an other way to use a custom editor here?


Solution

  • Since you cannot change the code of your class, you can register a new type descriptor for your class at run-time to provide custom type description.

    Using AssociatedMetadataTypeTypeDescriptionProvider you can create a type descriptor provider for your class that uses a metadata class to provide type description. Then you can register the provider using TypeDescriptor.AddProvider.

    Example

    Let's suppose the class which you cannot change its code is like this:

    public class MyClass
    {
        public MyClass()
        {
            List = new List<string>();
        }
        public string Name { get; set; }
        public List<string> List { get; set; }
    }
    

    The to solve the problem, you should define another class like that with the same properties and decorate those properties with attributes which you like, including the editor and converter attributes:

    public class MyClassMetadata
    {
        [DisplayName("Name Property")]
        public string Name { get; set; }
    
        [Editor(@"System.Windows.Forms.Design.StringCollectionEditor," +
            "System.Design, Version=2.0.0.0, Culture=neutral, " + 
            "PublicKeyToken=b03f5f7f11d50a3a",
            typeof(System.Drawing.Design.UITypeEditor))]
        public List<string> List { get; set; }
    }
    

    Then before showing the original class, register a new type descriptor provider for the original class which returns the metadata using the metadata class which we created:

    private void Form1_Load(object sender, EventArgs e)
    {
        var provider = new AssociatedMetadataTypeTypeDescriptionProvider(typeof(MyClass),
            typeof(MyClassMetadata));
        TypeDescriptor.AddProvider(provider, typeof(MyClass));
        this.propertyGrid1.SelectedObject = new MyClass();
    }
    

    I suppose you already have the CsvConverter from the first link:

    public class CsvConverter : TypeConverter
    {
        // Overrides the ConvertTo method of TypeConverter.
        public override object ConvertTo(ITypeDescriptorContext context,
           CultureInfo culture, object value, Type destinationType)
        {
            List<String> v = value as List<String>;
            if (destinationType == typeof(string))
            {
                return String.Join(",", v.ToArray()); 
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }