在 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
,下拉列表在每次打开时都会更新。
我正在 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
,下拉列表在每次打开时都会更新。