我正在尝试在 PropertyGrid 上显示组合框。我并不是指下拉字符串列表,因为我需要与描述相关联的所选项目的索引。 使用表单上的 ComboBox 控件很容易获得这一点,但我无法通过在 PropertyGrid 中发布 ComboBox 类型属性来获得相同的结果。
在下面我的代码中 我正在尝试在 PropertyGrid 上获取组合框。
public class Wrap {
private ComboBox _Combo = new ComboBox();
public Wrap() {
_Combo.SelectedIndexChanged += new System.EventHandler(Combo_SelectedIndexChanged);
_Combo.Items.Add(new Item() { Text = "Text1", Value = "Value1" });
_Combo.Items.Add(new Item() { Text = "Text2", Value = "Value2" });
_Combo.DisplayMember = "Text";
_Combo.ValueMember = "Value";
_Combo.SelectedIndex = 1;
}
private void Combo_SelectedIndexChanged(object sender, EventArgs e) {
ComboBox cb = sender as ComboBox;
int i = cb.SelectedIndex;
if (i < 0)
return;
Item it = cb.Items[i] as Item;
string s = it.Value;
}
public ComboBox Combo {
get { return _Combo; }
set {
// Temporary test to avoid "null" (the only selection possible from propertygrid)
if (value == null)
return;
_Combo = value;
}
}
}
public class Item {
public string Value { set; get; }
public string Text { set; get; }
}
假设这是一个 WinForms
PropertyGrid
,您不需要显式使用 ComboBox
控件:自定义 TypeConverter
会为您处理一切。
还请注意,通常仅当您需要存储一些原始基础值(例如在数据库中)以表示实际模型中的一些更高级别的实例时,才需要区分
DisplayMember
/ValueMember
ComboBox
但在 PropertyGrid
中你不需要它。您可以直接在网格中使用高级自定义类型。不过,如果需要,您可以选择解析低级“值成员”,如以下示例所示。
你没有提供例子,所以我编了一个。请注意属性或类型本身上方的
[TypeConverter(...)]
属性
public class MyClassToEditInAGrid
{
// some regular properties here
public string StringProp { get; set; }
public int IntProp { get; set; }
// [...]
// My special property with the 'ComboBox'.
// You can omit the TypeConverter here if it is defined globally for the type
[TypeConverter(typeof(ItemConverter))]
[Description("Either select an item or type the corresponding text or underlying value")]
public Item MySelectableProperty { get; set; }
}
请注意,您也可以“全局”为您的
Item
定义类型转换器:
// You can define the type converter also here so it is used by default for Item.
// Or, you can indicate it just in MyClassToEditInAGrid for the property as above.
[TypeConverter(typeof(ItemConverter))]
public class Item
{
public string Value { set; get; }
public string Text { set; get; }
public override string ToString() => Text;
}
public class ItemConverter : TypeConverter
{
// The predefined values
private static readonly Item[] _items =
{
new() { Text = "Text1", Value = "Value1" },
new() { Text = "Text2", Value = "Value2" },
new() { Text = "Text3", Value = "Value3" },
new() { Text = "Text4", Value = "Value4" },
};
// If your "ValueMember" is not a string, add its type as well (eg. int, some custom enum, etc.)
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) => destinationType == typeof(string);
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) => sourceType == typeof(string);
// Destination type is always string in a PropertyGrid but if your "ValueMember" is some different type you might want to add them, too
public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
{
if (destinationType != typeof(string) || value is not Item item)
return base.ConvertTo(context, culture, value, destinationType);
return item.Text;
}
// You might want to parse from Text and your "ValueMember". Both are strings in your example.
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
{
if (value is not string str)
return base.ConvertFrom(context, culture, value);
// 1. Parsing by text, case-insensitive
Item? result = _items.FirstOrDefault(i => String.Equals(i.Text, str, StringComparison.OrdinalIgnoreCase));
// 2. Parsing by value, case-sensitive
result ??= _items.FirstOrDefault(i => i.Value == str);
return result ?? throw new ArgumentException($"Invalid value: {str}", nameof(value));
}
// This enables "ComboBox" for the property
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true;
// This tells that it's not a simple read-only drop down but you can also type values to parse
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context) => false;
// This returns the items in the drop-down area
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) => new(_items);
}
将
PropertyGrid
放入 Form
中并像这样使用它:
public partial class CustomTypeConverterDemo : Form
{
public CustomTypeConverterDemo()
{
InitializeComponent();
var myObj = new MyClassToEditInAGrid();
propertyGrid1.SelectedObject = myObj;
}
}
展示项目选择和从键入的文本或值进行解析的结果: