自定义ComboBox抛出ArgumentOutOfRangeException

时间:2012-11-15 01:06:14

标签: c# combobox

我的自定义ComboBox源代码如下:

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)

任何人都可以帮我解决这个错误吗?

2 个答案:

答案 0 :(得分:0)

在选定值中,您试图强制值。但这个价值不在收集中。

答案 1 :(得分: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时,它调用原始的ComboBox.Items(保持为空)与非零的SelectedIndex并导致异常。

尝试在ObjectCollection上创建和使用包装器而不是创建新的ObjectCollection实例。 但是在包装器代码中,每次使用它之前都必须检查ObjectCollection实例的链接(或者你会得到ArgumentOutOfRangeException),因为ComboBox代码可以重新创建它而不允许覆盖create 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; }
    }
}

这是我自己的抽象通用ComboBox。