3

我的自定义组合框源如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;

namespace IHWinUtility
{
    public class IHComboBox : ComboBox
    {
        private IHComboBoxItems _ihComboBoxItems;

        public IHComboBox()
        {
            this.DropDownStyle = ComboBoxStyle.DropDownList;
            _ihComboBoxItems = new IHComboBoxItems(this);
        }

        new public IHComboBoxItems Items
        {
            get { return _ihComboBoxItems; }
            set { _ihComboBoxItems = (IHComboBoxItems)value; }
        }

        new public string SelectedValue
        {
            get { return this.SelectedItem == null ? "" : ((IHComboBoxItem)this.SelectedItem).Value.ToString(); }
        }
    }


    public class IHComboBoxItems : ComboBox.ObjectCollection
    {
        public IHComboBox _ihComboBox;

        public IHComboBoxItems(IHComboBox owner) : base(owner)
        {
            _ihComboBox = owner;
        }

        public int Add(string Text, object Value)
        {
            int _retValue = 0;

            IHComboBoxItem _item = new IHComboBoxItem();
            _item.Text = Text;
            _item.Value = Value;
            _ihComboBox.Items.Add(_item);

            _retValue = _ihComboBox.Items.Count;

            return _retValue;
        }

        new public void Insert(int index, object item)
        {

        }
    }


    public class IHComboBoxItem
    {
        public string Text { get; set; }
        public object Value { get; set; }

        public override string ToString()
        {
            return Text;
        }
    }
}

我在该组合框中添加了一些数据,如下所示:

    private void Form1_Load(object sender, EventArgs e)
    {
        this.ihComboBox1.Items.Add("Text1", "Value1");
    }

它工作得很好。我可以看到 Text1 绑定到我的 Combobox。但问题是当我通过单击 Combobox 中的箭头更改 selectedItem 时,它会抛出以下错误:

System.ArgumentOutOfRangeException was unhandled Message="InvalidArgument=Value of '0' is not valid for 'index'.
Parameter name: index
   at: System.ArgumentOutOfRangeException System.Windows.Forms.ComboBox.ObjectCollection.get_Item(Int32 index)
   at: System.Windows.Forms.ComboBox.get_SelectedItem()
   at: System.Windows.Forms.ComboBox.get_Text()
   at: System.Windows.Forms.ComboBox.WmReflectCommand(Message& m)
   at: System.Windows.Forms.ComboBox.WndProc(Message& m)
   at: System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at: System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at: System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

谁能帮我解决这个错误?

4

2 回答 2

0

在选定的值中,您试图强制一个值。但该值不在收藏中。

于 2012-12-11T09:36:53.327 回答
0

当您的代码调用 IHComboBoxItems::Add 方法时,新对象将被添加到 IHComboBox._ihComboBoxItems 集合中,与原始 ComboBox.Items 集合不同。原始 ComboBox.Items 将为空。

ComboBox.get_Text 使用 ComboBox.Items 属性通过当前 SelectedIndex 获取 SelectedItem。

下拉列表使用反射枚举 Items 集合,映射到新的 IHComboBoxItems.Items 属性(调用 Add 后不会为空),并允许用户选择非零 SelectedIndex,但原始 ComboBoxItems.Items 将保持为空。当内部 ComboBox 代码尝试加载 Text 时,它使用非零 SelectedIndex 调用原始 ComboBox.Items(保持为空)并导致异常。

尝试在 ObjectCollection 上创建和使用包装器,而不是创建新的 ObjectCollection 实例。但是在包装器代码中,您必须在每次使用它之前检查到 ObjectCollection 实例的链接(否则您将得到 ArgumentOutOfRangeException),因为 ComboBox 代码可以重新创建它并且不允许覆盖创建 ObjectCollection 实例构造。

代码示例:

public abstract class TypedComboBox<T> : ComboBox
{
    public TypedComboBox()
    {
        _objectCollectionProxy = new TypedObjectCollectionProxy<T>(this);
    }

    private TypedObjectCollectionProxy<T> _objectCollectionProxy;

    public ObjectCollection ObjectCollectionCollection
    {
        get { return base.Items; }
    }

    public class TypedObjectCollectionProxy<ItemType> : IList, IList<ItemType>, ICollection, ICollection<ItemType>, IEnumerable, IEnumerable<ItemType>
    {
        public ObjectCollection _objectCollection;
        private TypedComboBox<T> _owner;

        public TypedObjectCollectionProxy(TypedComboBox<T> owner)
        {
            this._owner = owner;
            this._objectCollection = owner.ObjectCollectionCollection;
        }

        /// <summary>Gets the number of items in the collection</summary>
        public int Count { get { return _objectCollection.Count; } }
        /// <summary>Gets a value indicating whether this collection can be modified</summary>
        public bool IsReadOnly { get { return _objectCollection.IsReadOnly; } }

        /// <summary>Retrieves the item at the specified index within the collection</summary>
        /// <param name="index">The index of the item in the collection to retrieve</param>
        /// <returns>An object representing the item located at the specified index within the collection</returns>
        /// <exception cref="System.ArgumentOutOfRangeException">The index was less than zero.-or- The index was greater than the count of
        ///                                                          items in the collection.</exception>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ItemType this[int index]
        {
            get
            {
                CheckItems();
                return (ItemType)_objectCollection[index];
            }
            set
            {
                CheckItems();
                _objectCollection[index] = value;
            }
        }

        public void CheckItems()
        {
            if (this._objectCollection != _owner.ObjectCollectionCollection)
                this._objectCollection = _owner.ObjectCollectionCollection;
        }

        /// <summary>Adds an item to the list of items for a System.Windows.Forms.ComboBox</summary>
        /// <param name="item">An object representing the item to add to the collection</param>
        /// <returns>The zero-based index of the item in the collection</returns>
        /// <exception cref="System.ArgumentNullException">The item parameter was null</exception>
        public int Add(ItemType item)
        {
            CheckItems();
            return _objectCollection.Add(item);
        }

        /// <summary>Adds an array of items to the list of items for a System.Windows.Forms.ComboBox</summary>
        /// <param name="items">An array of objects to add to the list</param>
        /// <exception cref="System.ArgumentNullException">An item in the items parameter was null</exception>
        public void AddRange(IEnumerable<ItemType> items)
        {
            CheckItems();
            _objectCollection.AddRange(items.Cast<object>().ToArray());
        }

        /// <summary>Removes all items from the System.Windows.Forms.ComboBox</summary>
        public void Clear()
        {
            CheckItems();
            _objectCollection.Clear();
        }

        /// <summary>Determines if the specified item is located within the collection</summary>
        /// <param name="value">An object representing the item to locate in the collection</param>
        /// <returns>true if the item is located within the collection; otherwise, false</returns>
        public bool Contains(ItemType value)
        {
            CheckItems();
            return _objectCollection.Contains(value);
        }

        /// <summary>Copies the entire collection into an existing array of objects at a specified location within the array</summary>
        /// <param name="destination">The object array to copy the collection to</param>
        /// <param name="arrayIndex">The location in the destination array to copy the collection to</param>
        public void CopyTo(object[] destination, int arrayIndex)
        {
            CheckItems();
            _objectCollection.CopyTo(destination, arrayIndex);
        }

        /// <summary>Returns an enumerator that can be used to iterate through the item collection</summary>
        /// <returns>An System.Collections.IEnumerator that represents the item collection</returns>
        public IEnumerator GetEnumerator()
        {
            CheckItems();
            return _objectCollection.GetEnumerator();
        }

        /// <summary>Retrieves the index within the collection of the specified item</summary>
        /// <param name="value">An object representing the item to locate in the collection</param>
        /// <returns>The zero-based index where the item is located within the collection; otherwise, -1</returns>
        /// <exception cref="System.ArgumentNullException">The value parameter was null</exception>
        public int IndexOf(ItemType value)
        {
            CheckItems();
            return _objectCollection.IndexOf(value);
        }

        /// <summary>Inserts an item into the collection at the specified index</summary>
        /// <param name="index">The zero-based index location where the item is inserted</param>
        /// <param name="item">An object representing the item to insert</param>
        /// <exception cref="System.ArgumentNullException">The item was null</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">The index was less than zero.-or- The index was greater than the count of items in the collection</exception>
        public void Insert(int index, ItemType item)
        {
            CheckItems();
            _objectCollection.Insert(index, item);
        }

        /// <summary>Removes the specified item from the System.Windows.Forms.ComboBox</summary>
        /// <param name="value">The System.Object to remove from the list</param>
        public bool Remove(ItemType value)
        {
            int kIndex = IndexOf(value);
            if (kIndex >= 0)
            {
                CheckItems();
                _objectCollection.RemoveAt(kIndex);
                return true;
            }
            return false;
        }

        /// <summary>Removes an item from the System.Windows.Forms.ComboBox at the specified index</summary>
        /// <param name="index">The index of the item to remove</param>
        /// <exception cref="System.ArgumentOutOfRangeException">The value parameter was less than zero.-or- The value parameter was greater than or equal to the count of items in the collection</exception>
        public void RemoveAt(int index)
        {
            CheckItems();
            _objectCollection.RemoveAt(index);
        }

        #region IList Members

        int IList.Add(object value)
        {
            return this.Add((ItemType)value);
        }

        void IList.Clear()
        {
            this.Clear();
        }

        bool IList.Contains(object value)
        {
            return this.Contains((ItemType)value);
        }

        int IList.IndexOf(object value)
        {
            return this.IndexOf((ItemType)value);
        }

        void IList.Insert(int index, object value)
        {
            this.Insert(index, (ItemType)value);
        }

        bool IList.IsFixedSize
        {
            get
            {
                CheckItems();
                return (_objectCollection as IList).IsFixedSize;
            }
        }

        bool IList.IsReadOnly
        {
            get { return this.IsReadOnly; }
        }

        void IList.Remove(object value)
        {
            this.Remove((ItemType)value);
        }

        void IList.RemoveAt(int index)
        {
            this.RemoveAt(index);
        }

        object IList.this[int index]
        {
            get
            {
                return this[index];
            }
            set
            {
                this[index] = (ItemType)value;
            }
        }

        #endregion

        #region ICollection Members

        void ICollection.CopyTo(Array array, int index)
        {
            this.CopyTo((object[])array, index);
        }

        int ICollection.Count
        {
            get { return this.Count; }
        }

        bool ICollection.IsSynchronized
        {
            get
            {
                CheckItems();
                return (_objectCollection as ICollection).IsSynchronized;
            }
        }

        object ICollection.SyncRoot
        {
            get
            {
                CheckItems();
                return (_objectCollection as ICollection).SyncRoot;
            }
        }

        #endregion

        #region IEnumerable<ItemType> Members

        IEnumerator<ItemType> IEnumerable<ItemType>.GetEnumerator()
        {
            CheckItems();
            return _objectCollection.Cast<ItemType>().GetEnumerator();
        }

        #endregion

        #region ICollection<ItemType> Members

        void ICollection<ItemType>.Add(ItemType item)
        {
            this.Add(item);
        }

        void ICollection<ItemType>.Clear()
        {
            this.Clear();
        }

        bool ICollection<ItemType>.Contains(ItemType item)
        {
            return this.Contains(item);
        }

        void ICollection<ItemType>.CopyTo(ItemType[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        int ICollection<ItemType>.Count
        {
            get { return this.Count; }
        }

        bool ICollection<ItemType>.IsReadOnly
        {
            get { return this.IsReadOnly; }
        }

        bool ICollection<ItemType>.Remove(ItemType item)
        {
            return this.Remove(item);
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }

    /// <summary>Gets an object representing the collection of the items contained in this System.Windows.Forms.ComboBox</summary>
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [Browsable(false)]
    [Bindable(true)]
    public new TypedObjectCollectionProxy<T> Items
    {
        get { return _objectCollectionProxy; }
    }

    /// <summary>Gets or sets currently selected item in the System.Windows.Forms.ComboBox</summary>
    [Bindable(true)]
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public new T SelectedItem
    {
        get { return (T)base.SelectedItem; }
        set { base.SelectedItem = value; }
    }
}

这是我自己的抽象通用组合框。

于 2015-10-01T09:58:35.260 回答