// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using Windows.Win32.UI.Accessibility; namespace System.Windows.Forms; public partial class ListViewItem { internal sealed class ListViewItemTileAccessibleObject : ListViewItemBaseAccessibleObject { private ListViewLabelEditAccessibleObject? _labelEditAccessibleObject; public ListViewItemTileAccessibleObject(ListViewItem owningItem) : base(owningItem) { } protected override View View => View.Tile; private ListViewLabelEditAccessibleObject? LabelEditAccessibleObject => _labelEditAccessibleObject ??= _owningListView._labelEdit is null ? null : new(_owningListView, _owningListView._labelEdit); internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) => direction switch { NavigateDirection.NavigateDirection_FirstChild => _owningListView._labelEdit is not null ? LabelEditAccessibleObject : GetChildInternal(1), NavigateDirection.NavigateDirection_LastChild => GetChildInternal(GetLastChildIndex()), _ => base.FragmentNavigate(direction), }; // Only additional ListViewSubItem are displayed in the accessibility tree if the ListView // in the "Tile" view (the first ListViewSubItem is responsible for the ListViewItem) public override AccessibleObject? GetChild(int index) { if (_owningListView.View != View.Tile) { throw new InvalidOperationException(string.Format(SR.ListViewItemAccessibilityObjectInvalidViewException, nameof(View.Tile))); } return GetChildInternal(index + 1); } internal override AccessibleObject? GetChildInternal(int index) { // If the ListView does not support ListViewSubItems, the index is greater than the number of columns // or the index is negative, then we return null if (!_owningListView.SupportsListViewSubItems || index <= 0 || _owningListView.Columns.Count <= index || _owningItem.SubItems.Count <= index || GetSubItemBounds(index).IsEmpty) { return null; } return _owningItem.SubItems[index].AccessibilityObject; } public override int GetChildCount() { if (_owningListView.View != View.Tile) { throw new InvalidOperationException(string.Format(SR.ListViewItemAccessibilityObjectInvalidViewException, nameof(View.Tile))); } if (!_owningListView.IsHandleCreated || !_owningListView.SupportsListViewSubItems) { return InvalidIndex; } if (_owningItem.SubItems.Count == 1) { return _owningListView._labelEdit is not null ? 1 : 0; } return _owningListView._labelEdit is not null ? GetLastChildIndex() + 1 : GetLastChildIndex(); } internal override int GetChildIndex(AccessibleObject? child) { if (child is null || !_owningListView.SupportsListViewSubItems || child == _owningItem.SubItems[0].AccessibilityObject || child is not ListViewSubItem.ListViewSubItemAccessibleObject subItemAccessibleObject || subItemAccessibleObject.OwningSubItem is null) { return InvalidIndex; } int index = _owningItem.SubItems.IndexOf(subItemAccessibleObject.OwningSubItem); return index == -1 || index > GetLastChildIndex() ? InvalidIndex : index; } private int GetLastChildIndex() { // Data about the first ListViewSubItem is displayed in the ListViewItem. // Therefore, it is not displayed in the ListViewSubItems list if (_owningItem.SubItems.Count == 1) { return InvalidIndex; } // Only ListViewSubItems with the corresponding columns are displayed in the ListView int subItemCount = Math.Min(_owningListView.Columns.Count, _owningItem.SubItems.Count); // The ListView can be of limited TileSize, so some of the ListViewSubItems can be hidden. // sListViewSubItems that do not have enough space to display have an empty bounds for (int i = 1; i < subItemCount; i++) { if (GetSubItemBounds(i).IsEmpty) { return i - 1; } } return subItemCount - 1; } internal override Rectangle GetSubItemBounds(int subItemIndex) => _owningListView.IsHandleCreated ? _owningListView.GetSubItemRect(_owningItem.Index, subItemIndex) : Rectangle.Empty; } } |