PropertyGrid 上的组合框

问题描述 投票:0回答:1

我正在尝试在 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; }
  }
c# combobox propertygrid typeconverter selectionchanged
1个回答
0
投票

假设这是一个 WinForms

PropertyGrid
,您不需要显式使用
ComboBox
控件:自定义
TypeConverter
会为您处理一切。

还请注意,通常仅当您需要存储一些原始基础值(例如在数据库中)以表示实际模型中的一些更高级别的实例时,才需要区分

DisplayMember
/
ValueMember
ComboBox
但在
PropertyGrid
中你不需要它。您可以直接在网格中使用高级自定义类型。不过,如果需要,您可以选择解析低级“值成员”,如以下示例所示。

1.绑定到 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;
}
2.类型转换器
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);
}
3.用途:

PropertyGrid
放入
Form
中并像这样使用它:

public partial class CustomTypeConverterDemo : Form
{
    public CustomTypeConverterDemo()
    {
        InitializeComponent();

        var myObj = new MyClassToEditInAGrid();
        propertyGrid1.SelectedObject = myObj;
    }
}

展示项目选择和从键入的文本或值进行解析的结果:

Custom TypeConverter

© www.soinside.com 2019 - 2024. All rights reserved.