// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
namespace System.Windows.Forms
{
public partial class ListBox
{
public class ObjectCollection : IList
{
private readonly ListBox owner;
private ItemArray items;
public ObjectCollection(ListBox owner)
{
this.owner = owner;
}
///
/// Initializes a new instance of ListBox.ObjectCollection based on another ListBox.ObjectCollection.
///
public ObjectCollection(ListBox owner, ObjectCollection value)
{
this.owner = owner;
AddRange(value);
}
///
/// Initializes a new instance of ListBox.ObjectCollection containing any array of objects.
///
public ObjectCollection(ListBox owner, object[] value)
{
this.owner = owner;
AddRange(value);
}
///
/// Retrieves the number of items.
///
public int Count
{
get
{
return InnerArray.GetCount(0);
}
}
///
/// Internal access to the actual data store.
///
internal ItemArray InnerArray
{
get
{
if (items == null)
{
items = new ItemArray(owner);
}
return items;
}
}
object ICollection.SyncRoot
{
get
{
return this;
}
}
bool ICollection.IsSynchronized
{
get
{
return false;
}
}
bool IList.IsFixedSize
{
get
{
return false;
}
}
public bool IsReadOnly
{
get
{
return false;
}
}
///
/// Adds an item to the List box. For an unsorted List box, the item is
/// added to the end of the existing list of items. For a sorted List box,
/// the item is inserted into the list according to its sorted position.
/// The item's toString() method is called to obtain the string that is
/// displayed in the List box.
/// A SystemException occurs if there is insufficient space available to
/// store the new item.
///
public int Add(object item)
{
int index = AddInternal(item);
return index;
}
private int AddInternal(object item)
{
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
int index = -1;
if (!owner.sorted)
{
InnerArray.Add(item);
}
else
{
if (Count > 0)
{
index = InnerArray.BinarySearch(item);
if (index < 0)
{
index = ~index; // getting the index of the first element that is larger than the search value
//this index will be used for insert
}
}
else
{
index = 0;
}
InnerArray.Insert(index, item);
}
bool successful = false;
try
{
if (owner.sorted)
{
}
else
{
index = Count - 1;
}
successful = true;
}
finally
{
if (!successful)
{
InnerArray.Remove(item);
}
}
return index;
}
int IList.Add(object item)
{
return Add(item);
}
public void AddRange(ObjectCollection value)
{
AddRangeInternal((ICollection)value);
}
public void AddRange(object[] items)
{
AddRangeInternal((ICollection)items);
}
internal void AddRangeInternal(ICollection items)
{
if (items == null)
{
throw new ArgumentNullException(nameof(items));
}
try
{
foreach (object item in items)
{
// adding items one-by-one for performance
// not using sort because after the array is sorted index of each newly added item will need to be found
// AddInternal is based on BinarySearch and finds index without any additional cost
AddInternal(item);
}
}
finally
{
}
}
///
/// Retrieves the item with the specified index.
///
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public virtual object this[int index]
{
get
{
if (index < 0 || index >= InnerArray.GetCount(0))
{
throw new ArgumentOutOfRangeException();
}
return InnerArray.GetItem(index, 0);
}
set
{
SetItemInternal(index, value);
}
}
///
/// Removes all items from the ListBox.
///
public virtual void Clear()
{
ClearInternal();
}
///
/// Removes all items from the ListBox. Bypasses the data source check.
///
internal void ClearInternal()
{
InnerArray.Clear();
}
public bool Contains(object value)
{
return IndexOf(value) != -1;
}
///
/// Copies the ListBox Items collection to a destination array.
///
public void CopyTo(object[] destination, int arrayIndex)
{
int count = InnerArray.GetCount(0);
for (int i = 0; i < count; i++)
{
destination[i + arrayIndex] = InnerArray.GetItem(i, 0);
}
}
void ICollection.CopyTo(Array destination, int index)
{
int count = InnerArray.GetCount(0);
for (int i = 0; i < count; i++)
{
destination.SetValue(InnerArray.GetItem(i, 0), i + index);
}
}
///
/// Returns an enumerator for the ListBox Items collection.
///
public IEnumerator GetEnumerator()
{
return InnerArray.GetEnumerator(0);
}
public int IndexOf(object value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
return InnerArray.IndexOf(value, 0);
}
internal int IndexOfIdentifier(object value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
return InnerArray.IndexOfIdentifier(value, 0);
}
///
/// Adds an item to the List box. For an unsorted List box, the item is
/// added to the end of the existing list of items. For a sorted List box,
/// the item is inserted into the list according to its sorted position.
/// The item's toString() method is called to obtain the string that is
/// displayed in the List box.
/// A SystemException occurs if there is insufficient space available to
/// store the new item.
///
public void Insert(int index, object item)
{
if (index < 0 || index > InnerArray.GetCount(0))
{
throw new ArgumentOutOfRangeException();
}
if (item == null)
{
throw new ArgumentNullException(nameof(item));
}
// If the List box is sorted, then nust treat this like an add
// because we are going to twiddle the index anyway.
//
if (owner.sorted)
{
Add(item);
}
else
{
InnerArray.Insert(index, item);
}
}
///
/// Removes the given item from the ListBox, provided that it is
/// actually in the list.
///
public void Remove(object value)
{
int index = InnerArray.IndexOf(value, 0);
if (index != -1)
{
RemoveAt(index);
}
}
///
/// Removes an item from the ListBox at the given index.
///
public void RemoveAt(int index)
{
if (index < 0 || index >= InnerArray.GetCount(0))
{
throw new ArgumentOutOfRangeException();
}
// Update InnerArray before calling NativeRemoveAt to ensure that when
// SelectedIndexChanged is raised (by NativeRemoveAt), InnerArray's state matches wrapped LB state.
InnerArray.RemoveAt(index);
}
internal void SetItemInternal(int index, object value)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (index < 0 || index >= InnerArray.GetCount(0))
{
throw new ArgumentOutOfRangeException();
}
InnerArray.SetItem(index, value);
}
} // end ObjectCollection}
}
}