使组合框仅接受特定类型

本文关键字:类型 组合 | 更新日期: 2023-09-27 18:21:50

我当前在Windows窗体应用程序中有一个组合框。为了指定组合框将包含哪些值,我将组合框的DataSource属性设置为某个数组,以便组合框包含该数组中的值。我还可以使用Items.Add()向ComboBox添加新值。但是,我想确保ComboBox可以填充一些特定类型的对象。因此,如果我有一个名为X的类,那么我想让它成为只有X类型的数组才能用作ComboBox的数据源。现在,ComboBox接受System.Object类型的对象。我怎样才能做到这一点?是否有ComboBox的属性需要设置为等于我的数据类型的名称?或者是否有一个事件会检查添加到我的组合框中的对象是否属于所需类型,如果不是,则会引发异常?

我正在考虑创建一个新类作为ComboBox的子类型,并重写Items属性的Add方法,以便Add检查其参数是否为所需类型(不确定是否以及如何执行)。即使我这样做了,仍然有其他方法可以向ComboBox中添加新值(AddRangeCopyTo等),所以我认为应该有一个更优雅的解决方案来解决这个问题。

使组合框仅接受特定类型

如果你想控制ComboBox可以包含的项的类型,你可以尝试创建一个新的类派生形式ComboBox,但你会遇到问题,它仍然有ComboBox.ObjectCollection Items属性,它仍然可以接受任何类型!不幸的是,Add方法不是虚拟的。

我能想到的唯一实用的解决方案是以某种方式抽象ComboBox。如果这不是共享代码,我建议您只创建一个用于向ComboBox添加项的方法。类似于:

// NOTE: All items that are added to comboBox1 need to be of type `SomeType`.
private void AddItemToComboBox(SomeType item)
{
    comboBox1.Items.Add(item);
}

任何将非SomeType对象添加到ComboBox的尝试都会遇到编译器错误。不幸的是,没有简单的方法可以阻止某人仍然直接向ComboBox.Items添加非SomeType项。

同样,如果这不是共享代码,那就不应该是一个真正的问题。

您可以通过
隐藏Items属性拥有自定义类型的Items属性,该属性以原始ItemsCollection 为参数

测试的示例类

public class Order
{
    public Int32 ID { get; set; }
    public string Reference { get; set; }
    public Order() { }
    public Order(Int32 inID, string inReference)
    {
        this.ID = inID;
        this.Reference = (inReference == null) ? string.Empty : inReference;
    }
    //Very important 
    //Because ComboBox using .ToString method for showing Items in the list
    public override string ToString()
    {
        return this.Reference;
    }
}

在下一个类中,我尝试将ComboBox的项集合包装为自己的类型。添加项目必须为混凝土类型在这里你可以添加你需要的其他方法/属性(删除)

public class ComboBoxList<TCustomType>
{
    private System.Windows.Forms.ComboBox.ObjectCollection _baseList;
    public ComboBoxList(System.Windows.Forms.ComboBox.ObjectCollection baseItems)
    {
        _baseList = baseItems;
    }
    public TCustomType this[Int32 index]
    {
        get { return (TCustomType)_baseList[index]; }
        set { _baseList[index] = value; }
    }
    public void Add(TCustomType item)
    {
        _baseList.Add(item);
    }
    public Int32 Count { get { return _baseList.Count; } }
}

这里是从combobox派生的自定义组合框类增加:通用型

public class ComboBoxCustomType<TCustomType> : System.Windows.Forms.ComboBox
{
    //Hide base.Items property by our wrapping class
    public new ComboBoxList<TCustomType> Items; 
    public ComboBoxCustomType() : base()
    {
        this.Items = new ComboBoxList<TCustomType>(base.Items);
    }
    public new TCustomType SelectedItem 
    { 
        get { return (TCustomType)base.SelectedItem; } 
    }
}

表单中使用的下一个代码

private ComboBoxCustomType<Order> _cmbCustom;
//this method used in constructor of the Form
private void ComboBoxCustomType_Initialize()
{
    _cmbCustom = new ComboBoxCustomType<Order>();
    _cmbCustom.Location = new Point(100, 20);
    _cmbCustom.Visible = true;
    _cmbCustom.DropDownStyle = ComboBoxStyle.DropDownList;
    _cmbCustom.Items.Add(new Order(0, " - nothing - "));
    _cmbCustom.Items.Add(new Order(1, "One"));
    _cmbCustom.Items.Add(new Order(2, "Three"));
    _cmbCustom.Items.Add(new Order(3, "Four"));
    _cmbCustom.SelectedIndex = 0;
    this.Controls.Add(_cmbCustom);
}

您可以重写usercontrol,添加一个ComboBox,然后只公开您希望使用的元素,而不是重写ComboBox(它不会像它的答案86中所说的那样工作)。类似的东西

public partial class MyComboBox<T> : UserControl where T: class
{
    public MyComboBox()
    {
        InitializeComponent();
    }
    public void Add(T item)
    {
        comboBox1.Items.Add(item);
    }
    public IEnumerable<T> Items
    {
        get { return comboBox1.Items.Cast<T>(); }
    }
}

然而,请注意,一些自动化软件依赖于访问底层控件,因此这可能会导致一些问题。

这种方法从不更改组合框的Items,因此它们仍将存储为objects,但当您访问它们时,您将它们强制转换为正确的类型,并且只允许添加该类型的它们。您可以通过创建新的组合框

 var myCB = new MyComboBox<ItemClass>();