在 PropertyGrid 中筛选枚举 属性 的下拉列表

Filter the dropdown list for an Enum property in PropertyGrid

我正在 PropertyGrid 中显示对象的属性。其中一个属性是一个枚举。因此它与一个组合框编辑器一起显示,其中列出了枚举的所有值。这一切都很好,但我需要在运行时过滤枚举值列表。我不能只用 Browsable 属性装饰一些枚举值,因为我想隐藏的值会有所不同。目前我倾向于自定义 UITypeEditor,但我认为我应该先咨询聪明人。

一个TypeConverter可能就是你所需要的,特别是如果合法子集"changes from moment to moment"。给定一个枚举:

public enum AnimalSpecies
{
    Canine, Feline, Rodent, Dragon, Unicorn, Robot
}

...用于 属性:

public class Animal
{
    ...
    [TypeConverter(typeof(AnimalSpeciesConverter))]
    public AnimalSpecies Species { get; set; }

如果修饰枚举,转换器将应用于使用它的 anything/everything;在 属性 上,它只影响那个。对于转换器,您需要覆盖 GetStandardValues():

class AnimalSpeciesConverter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        Animal test = context.Instance as Animal;

        if (test != null)
            return true;
        else
            return base.GetStandardValuesSupported();
    }

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        string[] names = Enum.GetNames(typeof(AnimalSpecies))
                           .Where(x => !x.StartsWith("Rob")).ToArray();

        return new StandardValuesCollection(names);
    }
}
  • GetStandardValuesSupported() return 为真表明 TypeConverter 可以并且将会提供这些值。
  • GetStandardValuesExclusive() 表示,用户不能选择输入自己的值。
  • GetStandardValues() 过滤列表并 return 新子集。

结果:

没有机器人!

如果过滤逻辑比较复杂,您可能希望让class实例确定内容。或者您可能只是希望该逻辑保留在 class 中。为此,我喜欢使用接口:

public interface IValuesProvider
{
    string[] GetValues();
}

public class Animal : IValuesProvider
{
    public string Name { get; set; }
    [TypeConverter(typeof(AnimalSpeciesConverter))]
    public AnimalSpecies Species { get; set; }
    public int Value { get; set; }
    ...
    public string[] GetValues()
    {
        List<string> names = Enum.GetNames(typeof(AnimalSpecies)).ToList();

        // your logic here
        if (Value < 10)
            names.Remove(AnimalSpecies.Feline.ToString());
        else if (Value < 50)
            names.Remove(AnimalSpecies.Robot.ToString());

        return names.ToArray();
    }

现在,当 PropertyGrid 请求值时,我们可以从实例中获取它们:

class AnimalSpeciesConverter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        IValuesProvider test = context.Instance as IValuesProvider;

        if (test != null)
            return true;
        else
            return base.GetStandardValuesSupported();
    }

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        IValuesProvider item = context.Instance as IValuesProvider;
        return new StandardValuesCollection(item.GetValues());
    }
}

作为替代方案,如果您不喜欢以这种方式公开并通过反射获取值,则可以跳过接口并将 GetValues 方法设为私有。在这种情况下,仅当该方法存在时,我才可能 return 对 GetStandardValuesSupported() 为真。这样一来,您就不会遇到 return 为 Get...Supported() 设置为真然后却无法提供它们的情况。

这是动态的:每次打开下拉列表时,值列表都是 refreshed/repolled。每次更改 Value,下拉列表在每次打开时都会更新。