【问题标题】:Make ComboBox accept only specific type使 ComboBox 只接受特定类型
【发布时间】:2014-09-13 22:13:53
【问题描述】:

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

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

【问题讨论】:

  • 您想要的想法是可能的,但您想由我们中的某个人完成?请尝试构建此组合框,如果遇到问题,请在此之后编写。
  • @mybirthname - 不,我只是想知道是否应该重写 ComboBox.ObjectCollection 的 Add 方法,或者是否有更优雅的方法来执行此操作,因为从技术上讲,我还需要重写其他方法可以向 ComboBox 添加新值的方法,例如 AddRange。
  • 您不能隐藏或覆盖Items 接受您的新类型,即使您从它继承;但您可以尝试将其包装在 UserControl 中并公开一个新项目集合。虽然会有很多代码来模拟/模仿现有的属性和集合。当然,CBo 已经接受了您的特定类型,而不仅仅是该类型
  • 我问只是因为我的好奇。为什么需要防止使用其他类型的 combobox?如果你对 combobox 事件中的项目做一些事情,那么你可以在你使用的每个事件处理程序中添加项目类型的检查......或者为这个控件命名为“ComboBoxOfMyType”,然后其他程序员会注意到这个组合框使用了一些类型。
  • @Fabio - 这是一个家庭作业,所以我必须这样做。您甚至提到了处理程序-每次将某些内容添加到 ComboBox 的项目时都会触发一个事件吗?如果是,那么我可以编写一个事件处理程序,当它看到 ComboBox.Items 中存在不正确类型的对象时将引发异常。

标签: c# .net winforms combobox


【解决方案1】:

如果您想控制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

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

【讨论】:

  • 非常感谢您的回复。我也是这么想的。我是 C# 新手,所以我不知道这是否可行 - 我可以将派生的 ComboBox 的 Items 属性设为私有,以便只能从 AddItemToComboBox() 方法中访问 Items 吗?我不认为这是可能的。我正在考虑的另一件事是创建一个新的(空)实现“Items”属性的 get 方法,但在 AddItemToComboBox() 方法中添加时使用 Items 属性的原始 get 方法。这可能吗?
【解决方案2】:

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

用于测试的示例类

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类派生自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);
}

【讨论】:

  • 是的,这种方法效果很好。我可以补充一点,ComboBoxList 不是从 ComboBox.ObjectCollection 派生的,因此它不包含 ObjectCollection 的其他方法,例如 AddRange 或 Remove。因此,为了真正模拟 ComboBox 功能,您必须按照您实现 Add() 的方式实现所有其他缺失的方法。
  • 您建议通过编程方式将此自定义组合框添加到表单(设置位置、可见属性等)。我在表单的工具箱中看不到这种派生的组合框,因为它使用泛型。是否可以使用工具箱添加此自定义组合框以形成表单,而不是以编程方式进行?
  • 尝试仅使用您的类型而不是通用类型来更改 ComboBox
  • 是的,只是我需要 Visual Studio Designer 中专门的通用组合框。
【解决方案3】:

您可以覆盖用户控件,为其添加一个组合框,然后只公开您希望使用的元素,而不是覆盖 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>();

【讨论】:

    猜你喜欢
    • 2022-10-04
    • 2016-12-14
    • 2015-03-28
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    相关资源
    最近更新 更多