-1

I would like to ask if it's possible to reuse the same TypeConverter when implementing a custom drop down list in a PropertyGrid, but with different items. Consider the following TypeConverter to implement a 2 item (dog/cat) drop down list in a PropertyGrid.

Public Class MyList : Inherits System.ComponentModel.StringConverter
    Public items As String() = New String() {"dog", "cat"} 

    Public Overloads Overrides Function GetStandardValues(ByVal context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
        Return New StandardValuesCollection(items)
    End Function

    Public Overloads Overrides Function GetStandardValuesSupported(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
        Return True
    End Function

    Public Overloads Overrides Function GetStandardValuesExclusive(ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
        Return True
    End Function
End Class

This TypeConverter is used as such:

<TypeConverter(GetType(MyList))>
Public Class MyDogAndCatList
   ...
End Class

I would now like to reuse this same TypeConverter MyList, but with different list items. Eg. instead of dog/cat, I'd like to use cow/sheep and then define the complex data class. Something like this:

cow_sheep = new MyList({"cow", "sheep"})
<TypeConverter(GetType(cow_sheep)), ...

However this doesn't seem possible because the TypeConverter must be a Class and cannot be an instance. I would like to reuse the TypeConverter because I have many lists to deal with and I don't want to define a new TypeConverter for each list while practically all overridden functions are always the same.

I understand I could build by base converter and then inherit from it to simplify my code a bit. But that would still mean dealing with more than 100 different classes, something I sure think is not the right approach.

Does anybody know how to do that? Any help is welcome. Thank you in advance.

dsula
  • 185
  • 1
  • 2
  • 8
  • You can't change the TypeConverterAttribute, but you can create another custom Attribute with a property that would define the list of values. Then you can get that attribute and its properties from your custom TypeConverter. – Simon Mourier Mar 26 '18 at 21:44
  • @Simon Thank you. Could you elaborate with some code how this can be done? I'm fairly new to modern programming, still half way stuck in 80's C (but I'm gettng better :-) – dsula Mar 26 '18 at 21:51
  • Hard to make sense of the question. A TypeConverter converts a type, in both cases it is MyList. That a MyList object has different property values must never matter. Be sure to make your TypeConverter work with it. – Hans Passant Mar 26 '18 at 23:31
  • @Hans: Currently I don't know better than to write TWO TypeConverter classes for my example. One for the dog/cat list, the other for the cow/sheep list. Each type converter class must contains all the overridden classes even though the only thing that changes is the list. How can I only change the list items, without having to write a new TypeCOnverter class. That's my question. I hope that makes it clearer. – dsula Mar 27 '18 at 00:21
  • Why are people downvoting this question? I'm here because I have a problem. If you downvote then at least tell me why. Each downvote reduces reputation which limits what I can do. – dsula Mar 27 '18 at 17:16

1 Answers1

0

You cannot change the TypeConverterAttribute to add something to it, but you can add any number of custom attributes to the property, so you can create your own attribute to hold custom data.

Here is some sample C# code:

public class Animals
{
    // both properties have the same TypeConverter, but they use different custom attributes
    [TypeConverter(typeof(ListTypeConverter))]
    [ListTypeConverter(new [] { "cat", "dog" })]
    public string Pets { get; set; }

    [TypeConverter(typeof(ListTypeConverter))]
    [ListTypeConverter(new [] { "cow", "sheep" })]
    public string Others { get; set; }
}

// this is your custom attribute
// Note attribute can only use constants (as they are added at compile time), so you can't add a List object here
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ListTypeConverterAttribute : Attribute
{
    public ListTypeConverterAttribute(string[] list)
    {
        List = list;
    }

    public string[] List { get; set; }
}

// this is the type converter that knows how to use the ListTypeConverterAttribute attribute
public class ListTypeConverter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        var list = new List<string>();

        // the context contains the property descriptor
        // the property descriptor has all custom attributes defined on the property
        // just get it (with proper null handling)
        var choices = context.PropertyDescriptor.Attributes.OfType<ListTypeConverterAttribute>().FirstOrDefault()?.List;
        if (choices != null)
        {
            list.AddRange(choices);
        }
        return new StandardValuesCollection(list);
    }
}
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298