Combobox配有强力打字物品

时间:2013-03-27 12:46:50

标签: c# winforms combobox

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

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

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

我无法弄明白,在Google上搜索产量几乎为零。

3 个答案:

答案 0 :(得分: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。如果您这样做并且使用了绑定列表,这些事件将自动转发到组合框,并且值也将在那里更新。

警告:在第一步中,BindingListNotifyPropertyChanged的使用效果非常好,但如果您要更改列表,则可能会遇到麻烦或者另一个线程中的对象属性(导致跨线程异常)。但也可以避免这种情况。

您只需要在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());

答案 1 :(得分:0)

我达到了我想要的目标:

  1. 创建仅允许添加TimeSpan值的自定义Combobox控件
  2. 使用自定义格式显示时间跨度值。
  3. 创建一个只接受一种类型的自定义组合框的方法似乎毫无用处。但是我需要在一个大型项目中使用它,其中经常使用具有时间跨度值的组合框。因此,在一个地方(一个班级,一个档案)保留所有必要的东西是最方便的。

    使用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));
    

    感谢您的帮助!

答案 2 :(得分:-1)

set {
    throw new NotImplementedException("I don't know why I put a setter here, because it doesn't really make sense");
}