Skip to content

Commit

Permalink
Fix Empty ListViewGroups are displayed in the Inspect tree #4779 (#4789)
Browse files Browse the repository at this point in the history
In this issue, we have two problems with invisible ListViewGroups and invisible ListViewItems.

An ListViewItem is considered invisible when it is in a ListViewGroup but not added to the ListView. In this case, the ListViewGroup contains data about it, but the ListViewItem is not displayed in the list. To solve this problem, the "GetVisibleItems" method was added, which returns a list of only displayed ListViewItems, in which the property "ListView" is not empty. Now, when receiving data about the ListViewItems of a ListViewGroup, we use this method and not "Items" property of the ListViewGroup.

The second issue, if the ListViewGroup is empty or contains invisible ListViewItems (case above), then this ListViewGroup is also not displayed in the ListView. This issue was solved in the same way as the issue above, by adding the "GetVisibleGroups" method that returns a list of only the displayed ListViewGroups.

Added unit tests for ListViewAccessibleObject, ListViewGroupAccessibleObject, ListViewItemAccessibleObject
  • Loading branch information
SergeySmirnov-Akvelon authored Apr 16, 2021
1 parent 970b01a commit f379253
Show file tree
Hide file tree
Showing 5 changed files with 822 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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.Generic;
using System.Drawing;
using static Interop;

Expand Down Expand Up @@ -108,7 +109,13 @@ internal override int[]? RuntimeId

public override AccessibleObject? GetChild(int index)
{
if (!_owningListView.IsHandleCreated || index < 0 || index >= GetChildCount())
if (!_owningListView.IsHandleCreated || index < 0)
{
return null;
}

IReadOnlyList<ListViewGroup> visibleGroups = GetVisibleGroups();
if (index >= GetChildCount(visibleGroups))
{
return null;
}
Expand All @@ -120,7 +127,7 @@ internal override int[]? RuntimeId

if (!OwnerHasDefaultGroup)
{
return _owningListView.Groups[index].AccessibilityObject;
return visibleGroups[index].AccessibilityObject;
}

// Default group has the last index out of the Groups.Count
Expand All @@ -129,7 +136,7 @@ internal override int[]? RuntimeId
// default group is the first before other groups.
return index == 0
? _owningListView.DefaultGroup.AccessibilityObject
: _owningListView.Groups[index - 1].AccessibilityObject;
: visibleGroups[index - 1].AccessibilityObject;
}

public override int GetChildCount()
Expand All @@ -139,9 +146,14 @@ public override int GetChildCount()
return 0;
}

return GetChildCount(GetVisibleGroups());
}

private int GetChildCount(IReadOnlyList<ListViewGroup> visibleGroups)
{
if (ShowGroupAccessibleObject)
{
return OwnerHasDefaultGroup ? _owningListView.Groups.Count + 1 : _owningListView.Groups.Count;
return OwnerHasDefaultGroup ? visibleGroups.Count + 1 : visibleGroups.Count;
}

return _owningListView.Items.Count;
Expand Down Expand Up @@ -282,6 +294,26 @@ internal override UiaCore.IRawElementProviderSimple[] GetSelection()
return selectedItemProviders;
}

internal IReadOnlyList<ListViewGroup> GetVisibleGroups()
{
List<ListViewGroup> list = new();
if (!ShowGroupAccessibleObject)
{
return list;
}

foreach (ListViewGroup listViewGroup in _owningListView.Groups)
{
if (listViewGroup.AccessibilityObject is ListViewGroup.ListViewGroupAccessibleObject listViewGroupAccessibleObject
&& listViewGroupAccessibleObject.GetVisibleItems().Count > 0)
{
list.Add(listViewGroup);
}
}

return list;
}

public override AccessibleObject? HitTest(int x, int y)
{
if (!_owningListView.IsHandleCreated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// 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.Generic;
using System.Drawing;
using static System.Windows.Forms.ListView;
using static Interop;
using static Interop.ComCtl32;

Expand All @@ -13,6 +15,7 @@ public partial class ListViewGroup
internal class ListViewGroupAccessibleObject : AccessibleObject
{
private readonly ListView _owningListView;
private readonly ListViewAccessibleObject _owningListViewAccessibilityObject;
private readonly ListViewGroup _owningGroup;
private readonly bool _owningGroupIsDefault;

Expand All @@ -26,6 +29,9 @@ public ListViewGroupAccessibleObject(ListViewGroup owningGroup, bool owningGroup
? _owningGroup.Items[0].ListView
: throw new InvalidOperationException(nameof(owningGroup.ListView)));

_owningListViewAccessibilityObject = _owningListView.AccessibilityObject as ListView.ListViewAccessibleObject
?? throw new InvalidOperationException(nameof(_owningListView.AccessibilityObject));

_owningGroupIsDefault = owningGroupIsDefault;
}

Expand All @@ -45,8 +51,8 @@ public override Rectangle Bounds
User32.SendMessageW(_owningListView, (User32.WM)ComCtl32.LVM.GETGROUPRECT, (IntPtr)CurrentIndex, ref groupRect);

return new Rectangle(
_owningListView.AccessibilityObject.Bounds.X + groupRect.left,
_owningListView.AccessibilityObject.Bounds.Y + groupRect.top,
_owningListViewAccessibilityObject.Bounds.X + groupRect.left,
_owningListViewAccessibilityObject.Bounds.Y + groupRect.top,
groupRect.right - groupRect.left,
groupRect.bottom - groupRect.top);
}
Expand Down Expand Up @@ -77,7 +83,7 @@ internal override int[]? RuntimeId
{
get
{
var owningListViewRuntimeId = _owningListView.AccessibilityObject.RuntimeId;
var owningListViewRuntimeId = _owningListViewAccessibilityObject.RuntimeId;
if (owningListViewRuntimeId is null)
{
return base.RuntimeId;
Expand Down Expand Up @@ -148,6 +154,20 @@ private bool GetNativeFocus()
_ => base.GetPropertyValue(propertyID)
};

internal IReadOnlyList<ListViewItem> GetVisibleItems()
{
List<ListViewItem> visibleItems = new();
foreach (ListViewItem listViewItem in _owningGroup.Items)
{
if (listViewItem.ListView is not null)
{
visibleItems.Add(listViewItem);
}
}

return visibleItems;
}

internal override UiaCore.IRawElementProviderFragment? FragmentNavigate(UiaCore.NavigateDirection direction)
{
if (!_owningListView.IsHandleCreated || _owningListView.VirtualMode)
Expand All @@ -158,11 +178,11 @@ private bool GetNativeFocus()
switch (direction)
{
case UiaCore.NavigateDirection.Parent:
return _owningListView.AccessibilityObject;
return _owningListViewAccessibilityObject;
case UiaCore.NavigateDirection.NextSibling:
return (_owningListView.AccessibilityObject as ListView.ListViewAccessibleObject)?.GetNextChild(this);
return _owningListViewAccessibilityObject.GetNextChild(this);
case UiaCore.NavigateDirection.PreviousSibling:
return (_owningListView.AccessibilityObject as ListView.ListViewAccessibleObject)?.GetPreviousChild(this);
return _owningListViewAccessibilityObject.GetPreviousChild(this);
case UiaCore.NavigateDirection.FirstChild:
int childCount = GetChildCount();
if (childCount > 0)
Expand Down Expand Up @@ -195,12 +215,13 @@ private bool GetNativeFocus()

if (!_owningGroupIsDefault)
{
if (index < 0 || index >= _owningGroup.Items.Count)
IReadOnlyList<ListViewItem> visibleItems = GetVisibleItems();
if (index < 0 || index >= visibleItems.Count)
{
return null;
}

return _owningGroup.Items[index].AccessibilityObject;
return visibleItems[index].AccessibilityObject;
}

foreach (ListViewItem? item in _owningListView.Items)
Expand Down Expand Up @@ -294,7 +315,7 @@ public override int GetChildCount()
}
else
{
return _owningGroup.Items.Count;
return GetVisibleItems().Count;
}
}

Expand Down
Loading

0 comments on commit f379253

Please sign in to comment.