使ComboBox仅接受特定类型

时间:2014-09-13 22:13:53

标签: c# .net winforms combobox

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

我正在考虑创建一个新类作为ComboBox的子类型,并覆盖Add属性的Items方法,以便Add检查其参数是否属于所需类型(不确定是否和我怎么能这样做)。即使我这样做,还有其他方法可以将新值添加到ComboBox(AddRangeCopyTo等),所以我认为应该有一个更优雅的解决方案来解决这个问题。

3 个答案:

答案 0 :(得分:2)

如果您想控制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对象的尝试都会遇到编译器错误。不幸的是,没有简单的方法可以阻止某人直接向SomeType添加非ComboBox.Items项。

同样,如果这不是共享代码,那么它应该不是问题。

答案 1 :(得分:1)

您可以通过您的<隐藏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);
}

答案 2 :(得分:0)

您可以覆盖usercontrol,向其添加一个组合框,然后只显示您希望使用的元素,而不是覆盖ComboBox(它不会像itsme86's answer中所述那样工作)。类似于

的东西
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>();