// 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.ComponentModel; namespace System.Windows.Forms { public partial class ListBox { // Should be "ObjectCollection", except we already have one of those. public class SelectedObjectCollection : IList { // This is the bitmask used within ItemArray to identify selected objects. internal static int SelectedObjectMask = ItemArray.CreateMask(); private readonly ListBox _owner; private bool stateDirty; private int lastVersion; private int count; public SelectedObjectCollection(ListBox owner) { _owner = owner ?? throw new ArgumentNullException(nameof(owner)); stateDirty = true; lastVersion = -1; } /// /// Number of current selected items. /// public int Count { get { // If the handle hasn't been created, we must do this the hard way. // Getting the count when using a mask is expensive, so cache it. // if (lastVersion != InnerArray.Version) { lastVersion = InnerArray.Version; count = InnerArray.GetCount(SelectedObjectMask); } return count; } } object ICollection.SyncRoot { get { return this; } } bool ICollection.IsSynchronized { get { return false; } } bool IList.IsFixedSize { get { return true; } } /// /// Called by the list box to dirty the selected item state. /// internal void Dirty() { stateDirty = true; } /// /// This is the item array that stores our data. We share this backing store /// with the main object collection. /// private ItemArray InnerArray { get { EnsureUpToDate(); return ((ObjectCollection)_owner.Items).InnerArray; } } /// /// This is the function that Ensures that the selections are uptodate with /// current listbox handle selections. /// internal void EnsureUpToDate() { if (stateDirty) { stateDirty = false; } } public bool IsReadOnly { get { return true; } } public bool Contains(object selectedObject) { return IndexOf(selectedObject) != -1; } public int IndexOf(object selectedObject) { return InnerArray.IndexOf(selectedObject, SelectedObjectMask); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } // A new internal method used in SelectedIndex getter... // For a Multi select ListBox there can be two items with the same name ... // and hence a object comparison is required... // This method returns the "object" at the passed index rather than the "item" ... // this "object" is then compared in the IndexOf( ) method of the itemsCollection. // internal object GetObjectAt(int index) { return InnerArray.GetEntryObject(index, SelectedObjectCollection.SelectedObjectMask); } /// /// Retrieves the specified selected item. /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public object this[int index] { get { return InnerArray.GetItem(index, SelectedObjectMask); } set { throw new NotSupportedException(); } } public void CopyTo(Array destination, int index) { int cnt = InnerArray.GetCount(SelectedObjectMask); for (int i = 0; i < cnt; i++) { destination.SetValue(InnerArray.GetItem(i, SelectedObjectMask), i + index); } } public IEnumerator GetEnumerator() { return InnerArray.GetEnumerator(SelectedObjectMask); } /// /// This method returns if the actual item index is selected. The index is the index to the MAIN /// collection, not this one. /// internal bool GetSelected(int index) { return InnerArray.GetState(index, SelectedObjectMask); } /// /// Same thing for GetSelected. /// internal void SetSelected(int index, bool value) { InnerArray.SetState(index, SelectedObjectMask, value); } public void Clear() { if (_owner != null) { _owner.ClearSelected(); } } public void Add(object value) { if (_owner != null) { ObjectCollection items = _owner.Items; if (items != null && value != null) { int index = items.IndexOf(value); if (index != -1 && !GetSelected(index)) { _owner.SelectedIndex = index; } } } } public void Remove(object value) { if (_owner != null) { ObjectCollection items = _owner.Items; if (items != null & value != null) { int index = items.IndexOf(value); if (index != -1 && GetSelected(index)) { _owner.SetSelected(index, false); } } } } } } }