PropertyGrid .NET winforms 中的 TypeConverter 重用

TypeConverter reuse in PropertyGrid .NET winforms

我想问一下,在 PropertyGrid 中实现自定义下拉列表时是否可以重用相同的 TypeConverter,但具有不同的项目。考虑以下 TypeConverter 在 PropertyGrid 中实现 2 项 (dog/cat) 下拉列表。

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

这个 TypeConverter 是这样使用的:

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

我现在想重用同一个 TypeConverter MyList,但使用不同的列表项。例如。我想使用 cow/sheep 而不是 dog/cat,然后定义复杂数据 class。像这样:

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

但这似乎不可能,因为 TypeConverter 必须是 Class 而不能是实例。我想重用 TypeConverter,因为我有很多列表要处理,我不想为每个列表定义一个新的 TypeConverter,而实际上所有被覆盖的函数总是相同的。

我知道我可以通过基础转换器构建然后继承它来稍微简化我的代码。但这仍然意味着要处理 100 多种不同的 classes,我认为这不是正确的方法。

有人知道怎么做吗?欢迎任何帮助。提前谢谢你。

您无法更改 TypeConverterAttribute 以向其添加内容,但您可以向 属性 添加任意数量的自定义属性,因此您可以创建自己的属性来保存自定义数据。

这是一些示例 C# 代码:

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);
    }
}