我的自定义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)
任何人都可以帮我解决这个错误吗?
答案 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。