A Generic Type TypeConverter – Property Editor to pick a type

To push the property grid to show a dropdown for a property, usually the best way is creating a TypeConverter for the prioperty. It basically Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties.

In this post I’ll show how you can create generic TypeConverter which shows a dropdown in property grid and allows you to pick all the types which are derived from the type that you specified in the generic parameter. So for example if you want to have a Form picker which allows you to pick from all the forms which are deriving from BaseForm, it will show something like this:

To do so, as I explained above, the first step is creating a new type converter by deriving from TypeConverter.

Then the next step is overriding GetStandardValues method of the TypeConverter and return the desired values.

Also you need to override GetStandardValuesSupported method and return true to determine this type converter can show dropdown.

It’s also a good idea to limit the editor just to select from the dropdown, by overrideing GetStandardValuesExclusive.

Then you need to get the desired types; There are two services that can help you at design-time to discover and resolve all types in the solution:

Now by knowing about above options, you can create a custom type converter to discover all form types in the project and list in the dropdown; and the usage will be something like this, easy and clean:

[TypeConverter(typeof(TypeTypeConverter<BaseForm>))]
public Type FormType { get; set; }

And here is the code for TypeTypeConverter<T>:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Linq;
public class TypeTypeConverter<T> : TypeConverter
{
    public override bool GetStandardValuesExclusive
          (ITypeDescriptorContext context)
    {
        return true;
    }
    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, CultureInfo culture, object value)
    {
        if (value is string)
            return GetTypeFromName(context, (string)value);
        return base.ConvertFrom(context, culture, value);
    }

    public override bool GetStandardValuesSupported
        (ITypeDescriptorContext context)
    {
        return true;
    }
    public override StandardValuesCollection GetStandardValues
        (ITypeDescriptorContext context)
    {
        return new StandardValuesCollection(GetProjectTypes(context)
            .OrderBy(x => x.FullName).ToList());
    }
    private List<Type> GetProjectTypes(IServiceProvider serviceProvider)
    {
        var typeDiscoverySvc = (ITypeDiscoveryService)serviceProvider
            .GetService(typeof(ITypeDiscoveryService));
        var types = typeDiscoverySvc.GetTypes(typeof(object), true)
            .Cast<Type>().Where(item =>
                item.IsPublic &&
                typeof(T).IsAssignableFrom(item) &&
                !item.IsAbstract &&
                !item.FullName.StartsWith("System")
            ).ToList();
        return types;
    }
    private Type GetTypeFromName(IServiceProvider 
        serviceProvider, string typeName)
    {
        ITypeResolutionService typeResolutionSvc =
            (ITypeResolutionService)serviceProvider
            .GetService(typeof(ITypeResolutionService));
        return typeResolutionSvc.GetType(typeName);
    }
}

You May Also Like

About the Author: Reza Aghaei

I’ve been a .NET developer since 2004. During these years, as a developer, technical lead and architect, I’ve helped organizations and development teams in design and development of different kind of applications including LOB applications, Web and Windows application frameworks and RAD tools. As a teacher and mentor, I’ve trained tens of developers in C#, ASP.NET MVC and Windows Forms. As an interviewer I’ve helped organizations to assess and hire tens of qualified developers. I really enjoy learning new things, problem solving, knowledge sharing and helping other developers. I'm usually active in .NET related tags in stackoverflow to answer community questions. I also share technical blog posts in my blog as well as sharing sample codes in GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *