1

我想创建一个从 ComboBox 继承的控件。我想要一个只接受某种类型的项目的组合框。

所以我需要否决 Items 属性。(注意新的关键字)。但是我在这个被否决的 Items 属性的设置区域中放置了什么?

    new public List<TimeSpanItemClass> Items
    {
        get
        {
            return base.Items.Cast<TimeSpanItemClass>().ToList();
        }
        set
        {
            ?
        }
    }

我想不通,在谷歌上搜索几乎一无所获。

4

3 回答 3

4

组合框已经支持这一点。

将您的元素列表放入属性中DataSource

var persons = new List<Person>();
// ToDo: fill list with some values...

myComboBox.DataSource = persons;

在属性中输入DisplayMember将代表用户应该看到的对象的属性。如果不设置,组合框将调用.ToString()所选元素。

myComboBox.DisplayMember = "FullName";

在属性中输入ValueMember您希望从代码中的对象接收的属性。如果不设置,组合框将返回对象本身。

myComboBox.ValueMember = "Born";

要从组合框中取出当前选定的对象,只需将属性SelectedValue转换为所需的类型。

private void OnComboBoxFormatSelectedIndexChanged(object sender, EventArgs e)
{
    DateTime born = (DateTime)comboBox.SelectedValue
}

分配后更改列表的更新

如果在将数据源分配给组合框后需要更改列表或其中的项目则必须通知组合框有关此更改。最简单的方法是简单地将数据源重新分配给组合框:

myComboBox.DataSource = persons;

更简洁的方法是,如果列表本身可以在发生任何更改时触发事件。此功能由 实现,BindingList<T>如果您通过添加或删除元素来更改列表,则组合框会自动更新。

信息流的下一步将是通知组合框是否更改了项目本身(在我们的示例中,例如一个人的姓氏)。要做到这一点,列表中的对象必须实现一个PropertyNameChanged事件(在我们的示例中,这将是 LastNameChanged,因为属性名称将是 LastName),或者您必须INotifyPropertyChanged在您的类中实现。如果您这样做并使用绑定列表,这些事件将自动转发到组合框,并且值也将在那里更新。

注意:在第一步中,aBindingList和的使用NotifyPropertyChanged效果很好,但是如果你要从另一个线程中更改列表或对象属性(导致跨线程异常),你真的会遇到麻烦。但也可以避免这种情况。

您只需要在 ComboBox 和 BindingList 之间再增加一层;一个BindingSource。这可以暂停和恢复通知链,以便您可以从另一个线程更改列表:

var persons = new BindingList<Person>();
var bindingSource = new BindingSource();
bindingSource.DataSource = persons;
comboBox.DataSource = bindingSource;

// Suspend change the list from another thread,
// and resume on the gui thread.
bindingSource.SuspendBinding();
Task.Factory.StartNew(() => persons.Add(Person.GetRandomFromDatabase()))
            .ContinueWith(finishedTask => bindingSource.ResumeBinding(),
                            TaskScheduler.FromCurrentSynchronizationContext());
于 2013-03-27T12:58:24.760 回答
0

我已经实现了我想要的:

  1. 创建仅允许添加 TimeSpan 值的自定义 Combobox 控件
  2. 以自定义格式显示时间跨度值。

一路创建只接受一种类型的自定义组合框似乎没用。但是我在一个经常使用具有时间跨度值的组合框的大型项目中需要它。因此,将所有必要的东西放在一个地方(一个类,一个文件)是最方便的。

通过使用 BindingList(以前从未使用过)。这是我的代码。

public partial class ComboBoxTimeSpan : ComboBox
{
    private BindingList<TimeSpanItemClass> _BindingList = new BindingList<TimeSpanItemClass>();

    public ComboBoxTimeSpan()
    {
        InitializeComponent();
        Items = new BindingList<TimeSpan>();
        this.Items.ListChanged += Items_ListChanged;
        this.DataSource = _BindingList;
    }

    void Items_ListChanged(object sender, ListChangedEventArgs e)
    {
        _BindingList.Clear();
        foreach (TimeSpan ts in Items)
        {
            _BindingList.Add(new TimeSpanItemClass(ts));
        }
    }

    /// <summary>
    /// The items in this combobox need to be of the type TimeSpan as this combobox is designed for showing time span values in easy to read text.
    /// </summary>
    new public BindingList<TimeSpan> Items
    {
        get;
        private set;
    }

    /// <summary>
    /// The ComboBoxTimeSpan has items that can all be converted to a time span.
    /// They will display as 1 hour, 2 hours, 1 minute, 1 hour and 2 minutes, 1 day, 2 weeks and 3 days, 3 days, etc...
    /// Its precise on the microsecond, no less
    /// </summary>
    private class TimeSpanItemClass : Object
    {
        /// <summary>
        /// The timespan that this object represents
        /// </summary>
        public TimeSpan timespan
        {
            get;
            set;
        }

        /// <summary>
        /// The constructor of this class needs a TimeSpan object
        /// </summary>
        public TimeSpanItemClass(TimeSpan ts)
        {
            timespan = ts;
        }

        /// <summary>
        /// The textual represention of the time span that this object represents.
        /// </summary>
        /// <returns>A string by a simple format</returns>
        public override string ToString()
        {
            //Specify your custom format here
            return timespan.ToString();
        }
    }
}  

现在组合框可以用作

cbts = new ComboBoxTimeSpan();
ctbs.Add(TimeSpan.FromDays(1));

感谢所有的帮助!

于 2013-03-27T14:56:21.447 回答
0
set {
    throw new NotImplementedException("I don't know why I put a setter here, because it doesn't really make sense");
}
于 2013-03-27T12:51:50.050 回答