File: System\Windows\Forms\Controls\DataGridView\DataGridViewComboBoxCell.ObjectCollection.cs
Web Access
Project: src\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.ComponentModel;
 
namespace System.Windows.Forms;
 
public partial class DataGridViewComboBoxCell : DataGridViewCell
{
    /// <summary>
    ///  A collection that stores objects.
    /// </summary>
    [ListBindable(false)]
    public class ObjectCollection : IList
    {
        private readonly DataGridViewComboBoxCell _owner;
        private List<object>? _items;
        private IComparer<object>? _comparer;
 
        public ObjectCollection(DataGridViewComboBoxCell owner)
        {
            Debug.Assert(owner is not null);
            _owner = owner;
        }
 
        private IComparer<object> Comparer => _comparer ??= new ItemComparer(_owner);
 
        /// <summary>
        ///  Retrieves the number of items.
        /// </summary>
        public int Count => InnerArray.Count;
 
        /// <summary>
        ///  Internal access to the actual data store.
        /// </summary>
        internal List<object> InnerArray => _items ??= [];
 
        object ICollection.SyncRoot => ((ICollection)InnerArray).SyncRoot;
 
        bool ICollection.IsSynchronized => ((ICollection)InnerArray).IsSynchronized;
 
        bool IList.IsFixedSize => ((IList)InnerArray).IsFixedSize;
 
        public bool IsReadOnly => ((IList)InnerArray).IsReadOnly;
 
        /// <summary>
        ///  Adds an item to the collection. For an unsorted combo box, the item is
        ///  added to the end of the existing list of items. For a sorted combo 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 combo box.
        /// </summary>
        public int Add(object item)
        {
            _owner.CheckNoDataSource();
 
            ArgumentNullException.ThrowIfNull(item);
 
            int index = ((IList)InnerArray).Add(item);
 
            bool success = false;
            if (_owner.Sorted)
            {
                try
                {
                    InnerArray.Sort(Comparer);
                    index = InnerArray.IndexOf(item);
                    success = true;
                }
                finally
                {
                    if (!success)
                    {
                        InnerArray.Remove(item);
                    }
                }
            }
 
            _owner.OnItemsCollectionChanged();
            return index;
        }
 
        int IList.Add(object? item) => Add(item!);
 
        public void AddRange(params object[] items)
        {
            _owner.CheckNoDataSource();
            AddRangeInternal(items);
            _owner.OnItemsCollectionChanged();
        }
 
        public void AddRange(ObjectCollection value)
        {
            _owner.CheckNoDataSource();
 
            InnerAddRange(value);
 
            _owner.OnItemsCollectionChanged();
 
            void InnerAddRange(ObjectCollection items)
            {
                ArgumentNullException.ThrowIfNull(items);
 
                foreach (object item in items)
                {
                    if (item is null)
                    {
                        throw new InvalidOperationException(SR.InvalidNullItemInCollection);
                    }
 
                    InnerArray.Add(item);
                }
 
                if (_owner.Sorted)
                {
                    InnerArray.Sort(Comparer);
                }
            }
        }
 
        /// <summary>
        ///  Add range that bypasses the data source check.
        /// </summary>
        internal void AddRangeInternal(ICollection<object> items)
        {
            ArgumentNullException.ThrowIfNull(items);
 
            foreach (object item in items)
            {
                if (item is null)
                {
                    throw new InvalidOperationException(SR.InvalidNullItemInCollection);
                }
            }
 
            // Add everything to the collection first, then sort
            InnerArray.AddRange(items);
            if (_owner.Sorted)
            {
                InnerArray.Sort(Comparer);
            }
        }
 
        internal void SortInternal() => InnerArray.Sort(Comparer);
 
        /// <summary>
        ///  Retrieves the item with the specified index.
        /// </summary>
        public virtual object? this[int index]
        {
            get
            {
                ArgumentOutOfRangeException.ThrowIfNegative(index);
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, InnerArray.Count);
 
                return InnerArray[index];
            }
            set
            {
                _owner.CheckNoDataSource();
 
                ArgumentOutOfRangeException.ThrowIfNegative(index);
                ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, InnerArray.Count);
 
                InnerArray[index] = value.OrThrowIfNull();
                _owner.OnItemsCollectionChanged();
            }
        }
 
        /// <summary>
        ///  Removes all items from the collection.
        /// </summary>
        public void Clear()
        {
            if (InnerArray.Count > 0)
            {
                _owner.CheckNoDataSource();
                InnerArray.Clear();
                _owner.OnItemsCollectionChanged();
            }
        }
 
        internal void ClearInternal() => InnerArray.Clear();
 
        public bool Contains(object? value) => IndexOf(value!) != -1;
 
        /// <summary>
        ///  Copies the DataGridViewComboBoxCell Items collection to a destination array.
        /// </summary>
        public void CopyTo(object[] destination, int arrayIndex) =>
            ((ICollection)InnerArray).CopyTo(destination, arrayIndex);
 
        void ICollection.CopyTo(Array destination, int index) =>
            ((ICollection)InnerArray).CopyTo(destination, index);
 
        /// <summary>
        ///  Returns an enumerator for the DataGridViewComboBoxCell Items collection.
        /// </summary>
        public IEnumerator GetEnumerator() => InnerArray.GetEnumerator();
 
        public int IndexOf(object? value)
        {
            ArgumentNullException.ThrowIfNull(value);
 
            return InnerArray.IndexOf(value);
        }
 
        /// <summary>
        ///  Adds an item to the collection. For an unsorted combo box, the item is
        ///  added to the end of the existing list of items. For a sorted combo 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 combo box.
        /// </summary>
        public void Insert(int index, object? item)
        {
            _owner.CheckNoDataSource();
 
            ArgumentNullException.ThrowIfNull(item);
            ArgumentOutOfRangeException.ThrowIfNegative(index);
            ArgumentOutOfRangeException.ThrowIfGreaterThan(index, InnerArray.Count);
 
            // If the combo box is sorted, then just treat this like an add
            // because we are going to twiddle the index anyway.
            if (_owner.Sorted)
            {
                Add(item);
            }
            else
            {
                InnerArray.Insert(index, item);
                _owner.OnItemsCollectionChanged();
            }
        }
 
        /// <summary>
        ///  Removes the given item from the collection, provided that it is
        ///  actually in the list.
        /// </summary>
        public void Remove(object? value)
        {
            int index = InnerArray.IndexOf(value!);
 
            if (index != -1)
            {
                RemoveAt(index);
            }
        }
 
        /// <summary>
        ///  Removes an item from the collection at the given index.
        /// </summary>
        public void RemoveAt(int index)
        {
            _owner.CheckNoDataSource();
 
            ArgumentOutOfRangeException.ThrowIfNegative(index);
            ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, InnerArray.Count);
 
            InnerArray.RemoveAt(index);
            _owner.OnItemsCollectionChanged();
        }
    }
}