File: System\Windows\Forms\Controls\ListView\ListViewGroupCollection.cs
Web Access
Project: src\src\System.Windows.Forms\src\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;
 
/// <summary>
///  A collection of listview groups.
/// </summary>
[ListBindable(false)]
public class ListViewGroupCollection : IList
{
    private readonly ListView _listView;
 
    private List<ListViewGroup>? _list;
 
    internal ListViewGroupCollection(ListView listView)
    {
        _listView = listView;
    }
 
    public int Count => List.Count;
 
    object ICollection.SyncRoot => this;
 
    bool ICollection.IsSynchronized => true;
 
    bool IList.IsFixedSize => false;
 
    bool IList.IsReadOnly => false;
 
    private List<ListViewGroup> List => _list ??= [];
 
    public ListViewGroup this[int index]
    {
        get => List[index];
        set
        {
            ArgumentNullException.ThrowIfNull(value);
 
            if (List.Contains(value))
            {
                return;
            }
 
            CheckListViewItems(value);
            value.ListView = _listView;
            List[index] = value;
        }
    }
 
    public ListViewGroup? this[string key]
    {
        get
        {
            if (_list is null)
            {
                return null;
            }
 
            for (int i = 0; i < _list.Count; i++)
            {
                if (string.Equals(key, this[i].Name, StringComparison.CurrentCulture))
                {
                    return this[i];
                }
            }
 
            return null;
        }
        set
        {
            ArgumentNullException.ThrowIfNull(value);
 
            if (_list is null)
            {
                // nothing to do
                return;
            }
 
            int index = -1;
            for (int i = 0; i < _list.Count; i++)
            {
                if (string.Equals(key, this[i].Name, StringComparison.CurrentCulture))
                {
                    index = i;
                    break;
                }
            }
 
            if (index != -1)
            {
                _list[index] = value;
            }
        }
    }
 
    object? IList.this[int index]
    {
        get => this[index];
        set
        {
            if (value is ListViewGroup group)
            {
                this[index] = group;
            }
        }
    }
 
    public int Add(ListViewGroup group)
    {
        ArgumentNullException.ThrowIfNull(group);
        ThrowInvalidOperationExceptionIfVirtualMode();
 
        if (Contains(group))
        {
            return -1;
        }
 
        CheckListViewItems(group);
        group.ListView = _listView;
        int index = ((IList)List).Add(group);
        if (_listView.IsHandleCreated)
        {
            _listView.InsertGroupInListView(List.Count, group);
            MoveGroupItems(group);
        }
 
        return index;
    }
 
    public ListViewGroup Add(string? key, string? headerText)
    {
        ListViewGroup group = new(key, headerText);
        Add(group);
        return group;
    }
 
    int IList.Add(object? value)
    {
        if (value is not ListViewGroup group)
        {
            throw new ArgumentException(SR.ListViewGroupCollectionBadListViewGroup, nameof(value));
        }
 
        return Add(group);
    }
 
    public void AddRange(params ListViewGroup[] groups)
    {
        ArgumentNullException.ThrowIfNull(groups);
        ThrowInvalidOperationExceptionIfVirtualMode();
 
        for (int i = 0; i < groups.Length; i++)
        {
            Add(groups[i]);
        }
    }
 
    public void AddRange(ListViewGroupCollection groups)
    {
        ArgumentNullException.ThrowIfNull(groups);
        ThrowInvalidOperationExceptionIfVirtualMode();
 
        for (int i = 0; i < groups.Count; i++)
        {
            Add(groups[i]);
        }
    }
 
    private void CheckListViewItems(ListViewGroup group)
    {
        for (int i = 0; i < group.Items.Count; i++)
        {
            ListViewItem item = group.Items[i];
            if (item.ListView is not null && item.ListView != _listView)
            {
                throw new ArgumentException(string.Format(SR.OnlyOneControl, item.Text));
            }
        }
    }
 
    public void Clear()
    {
        if (_listView.IsHandleCreated)
        {
            for (int i = 0; i < Count; i++)
            {
                _listView.RemoveGroupFromListView(this[i]);
            }
        }
 
        // Dissociate groups from the ListView
        for (int i = 0; i < Count; i++)
        {
            this[i].ListView = null;
            this[i].ReleaseUiaProvider();
        }
 
        List.Clear();
 
        // we have to tell the listView that there are no more groups
        // so the list view knows to remove items from the default group
        _listView.UpdateGroupView();
    }
 
    public bool Contains(ListViewGroup value) => List.Contains(value);
 
    bool IList.Contains(object? value)
    {
        if (value is not ListViewGroup group)
        {
            return false;
        }
 
        return Contains(group);
    }
 
    public void CopyTo(Array array, int index) => ((ICollection)List).CopyTo(array, index);
 
    public IEnumerator GetEnumerator() => List.GetEnumerator();
 
    public int IndexOf(ListViewGroup value) => List.IndexOf(value);
 
    int IList.IndexOf(object? value)
    {
        if (value is not ListViewGroup group)
        {
            return -1;
        }
 
        return IndexOf(group);
    }
 
    public void Insert(int index, ListViewGroup group)
    {
        ArgumentNullException.ThrowIfNull(group);
        ThrowInvalidOperationExceptionIfVirtualMode();
 
        if (Contains(group))
        {
            return;
        }
 
        CheckListViewItems(group);
        group.ListView = _listView;
        List.Insert(index, group);
        if (_listView.IsHandleCreated)
        {
            _listView.InsertGroupInListView(index, group);
            MoveGroupItems(group);
        }
    }
 
    void IList.Insert(int index, object? value)
    {
        if (value is ListViewGroup group)
        {
            Insert(index, group);
        }
    }
 
    private void MoveGroupItems(ListViewGroup group)
    {
        Debug.Assert(_listView.IsHandleCreated, "MoveGroupItems pre-condition: listView handle must be created");
 
        foreach (ListViewItem item in group.Items)
        {
            if (item.ListView == _listView)
            {
                item.UpdateStateToListView(item.Index);
            }
        }
    }
 
    public void Remove(ListViewGroup group)
    {
        if (!List.Remove(group))
        {
            return;
        }
 
        group.ListView = null;
        group.ReleaseUiaProvider();
 
        if (_listView.IsHandleCreated)
        {
            _listView.RemoveGroupFromListView(group);
        }
    }
 
    void IList.Remove(object? value)
    {
        if (value is ListViewGroup group)
        {
            Remove(group);
        }
    }
 
    public void RemoveAt(int index) => Remove(this[index]);
 
    private void ThrowInvalidOperationExceptionIfVirtualMode()
    {
        if (_listView.VirtualMode)
        {
            throw new InvalidOperationException(SR.ListViewCannotAddGroupsToVirtualListView);
        }
    }
}