1

ComboBox を継承するコントロールを作成したいと考えています。特定のタイプのアイテムのみを受け入れるコンボボックスが必要です。

そこで、Items プロパティを無効にする必要があります。(新しいキーワードに注意してください)。しかし、この却下された Items プロパティの set 領域には何を入れればよいでしょうか?

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

私はそれを理解することができず、Google で検索してもほとんど何も得られません。

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イベントを実装するか (この例では、プロパティ名が LastName であるため LastNameChanged になります) 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
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 に答える
0

私が望んでいたことを達成しました:

  1. TimeSpan 値の追加のみを許可するカスタム コンボボックス コントロールの作成
  2. カスタム形式で期間値を表示します。

1 つの型だけを受け入れるカスタム コンボボックスをわざわざ作成するのは無意味に思えるかもしれません。しかし、タイムスパン値を持つコンボボックスが頻繁に使用される大きなプロジェクトでこれが必要です。したがって、必要なものをすべて 1 つの場所 (1 つのクラス、1 つのファイル) に保持するのが最も便利です。

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 に答える