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

C# 筛选PropertyGrid中枚举属性的下拉列表,c#,.net,enums,propertygrid,C#,.net,Enums,Propertygrid,我正在PropertyGrid中显示对象的属性。这些属性之一是枚举。因此,它将与列出枚举的所有值的组合框编辑器一起显示。这很好,但我需要在运行时过滤枚举值列表。我不能仅仅用Browsable属性装饰一些枚举值,因为我想隐藏的值会有所不同。目前,我倾向于使用自定义UITypeEditor,但我认为我应该先与聪明人核实一下。aTypeConverter可能是您所需要的全部,尤其是如果合法子集“每时每刻都在变化”的话。给定一个枚举: public enum AnimalSpecies { Ca

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

a
TypeConverter
可能是您所需要的全部,尤其是如果合法子集“每时每刻都在变化”的话。给定一个枚举:

public enum AnimalSpecies
{
    Canine, Feline, Rodent, Dragon, Unicorn, Robot
}
…用于财产的:

public class Animal
{
    ...
    [TypeConverter(typeof(AnimalSpeciesConverter))]
    public AnimalSpecies Species { get; set; }
如果装饰枚举,转换器将应用于使用它的任何东西;在属性上,它仅影响该属性。对于转换器,您需要覆盖
GetStandardValues()

  • GetStandardValuesSupported()
    返回true以指示
    TypeConverter
    可以并将提供值
  • getStandardValuesEnclusive()
    表示用户不能选择键入自己的值
  • GetStandardValues()
    过滤列表并返回新的子集
结果:

没有机器人

如果过滤逻辑更复杂,您可能希望让类实例确定内容。或者,也许你更愿意把这种逻辑留在课堂上。为此,我喜欢使用界面:

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();
    }
另一种选择是,如果您不喜欢以这种方式公开
GetValues
方法并通过反射获取值,则可以跳过该接口,将该方法设置为私有。在这种情况下,只有当方法存在时,我才可能为
GetStandardValuesSupported()
返回true。这样,您就不会遇到这样的情况:您为
Get…Supported()
返回true,然后又无法提供它们


这是动态的:每次打开下拉列表时,都会刷新/重新填充值列表。每次更改
值时,下拉列表都会在每次打开时更新。

为什么选择此筛选器?其中一些在运行时不合法吗?部分类和枚举的代码对于上下文来说很好。是的,适当的枚举值集每时每刻都在变化。我刚用了一个自定义UITypeEditor。这是一个示例,尽管它解决了一个稍有不同的问题(不允许的枚举值不会发生变化)(我认为在没有自定义编辑器的情况下,Browsable属性也会发生变化)。在我的例子中,我只是将所需的项目添加到EditValue()中的列表框中。Simon的回答不允许“每时每刻”进行更改。一个类型转换器可能更合适更有趣!非常感谢你周到的回答。我在自定义UITypeEditor方面也取得了成功,在自定义UITypeEditor中,EditValue()被覆盖,以获取当前适当的值列表并将其添加到列表框中;下拉列表每次打开时都会更新。但这当然更好。我完全忘记了TypeConverter除了用于转换类型的方法外,还有其他方法可以重写;-)做大多数事情的方法很多,很难知道哪种方法最有效。非常有用的答案。我使用动态值选择方法制作了一个抽象枚举转换器:公共类EnumValueSelector或TypeConverter。。。受保护的虚拟bool SelectIsStandardValuesByContextInstance(对象上下文实例,输出标准值集合值)。。。还有一个字符串转换方法:受保护的虚拟IEnumerable ConvertSelectionToString(IEnumerable selection)。。。
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();
    }
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());
    }
}