Skip to content

Make sure the Label Edit in ListView has correct position in accessibility tree #9782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ internal override UiaCore.RowOrColumnMajor RowOrColumnMajor
return null;
}

if (owningListView._labelEdit is {} labelEdit && index == GetChildCount() - 1)
{
return labelEdit.AccessibilityObject;
}

if (owningListView.GroupsDisplayed)
{
IReadOnlyList<ListViewGroup> visibleGroups = GetVisibleGroups();
Expand All @@ -117,10 +112,6 @@ public override int GetChildCount()
}

int count = owningListView.GroupsDisplayed ? GetVisibleGroups().Count : owningListView.Items.Count;
if (owningListView._labelEdit is not null)
{
count++;
}

return count;
}
Expand Down Expand Up @@ -167,9 +158,7 @@ internal override int GetChildIndex(AccessibleObject? child)
return base.GetChildIndex(child);
}

return owningListView._labelEdit is { } labelEdit && child == labelEdit.AccessibilityObject
? GetChildCount() - 1
: owningListView.GroupsDisplayed ? GetGroupIndex(child) : GetItemIndex(child);
return owningListView.GroupsDisplayed ? GetGroupIndex(child) : GetItemIndex(child);
}

private string GetItemStatus()
Expand Down Expand Up @@ -239,11 +228,6 @@ internal override string GetMultiViewProviderViewName(int viewId)
return null;
}

if (owningListView._labelEdit is {} labelEdit)
{
return labelEdit.AccessibilityObject;
}

if (owningListView.GroupsDisplayed)
{
IReadOnlyList<ListViewGroup> visibleGroups = GetVisibleGroups();
Expand Down
23 changes: 14 additions & 9 deletions src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using System.Windows.Forms.VisualStyles;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using static System.Windows.Forms.ListViewGroup;
using static System.Windows.Forms.ListViewItem;
using static Interop;
using static Interop.ComCtl32;

Expand Down Expand Up @@ -175,7 +176,10 @@ public partial class ListView : Control

private bool _blockLabelEdit;

private ListViewLabelEditNativeWindow? _labelEdit;
internal ListViewLabelEditNativeWindow? _labelEdit;

// Used to record the SubItem to which the Label Edit belongs.
internal ListViewSubItem? _listViewSubItem;

// Background image stuff
// Because we have to create a temporary file and the OS does not clean up the temporary files from the machine
Expand Down Expand Up @@ -3394,24 +3398,24 @@ public void EnsureVisible(int index)
// win32 listView control can't search inside sub items
for (int i = startIndex; i < Items.Count; i++)
{
ListViewItem lvi = Items[i];
for (int j = 0; j < lvi.SubItems.Count; j++)
ListViewItem listViewItem = Items[i];
for (int j = 0; j < listViewItem.SubItems.Count; j++)
{
ListViewItem.ListViewSubItem lvsi = lvi.SubItems[j];
ListViewSubItem listViewSubItem = listViewItem.SubItems[j];
// the win32 list view search for items w/ text is case insensitive
// do the same for sub items
// because we are comparing user defined strings we have to do the slower String search
// ie, use String.Compare(string, string, case sensitive, CultureInfo)
// instead of new Whidbey String.Equals overload
// String.Equals(string, string, StringComparison.OrdinalIgnoreCase
if (string.Equals(text, lvsi.Text, StringComparison.OrdinalIgnoreCase))
if (string.Equals(text, listViewSubItem.Text, StringComparison.OrdinalIgnoreCase))
{
return lvi;
return listViewItem;
}

if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(lvsi.Text, text, CompareOptions.IgnoreCase))
if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(listViewSubItem.Text, text, CompareOptions.IgnoreCase))
{
return lvi;
return listViewItem;
}
}
}
Expand Down Expand Up @@ -3825,7 +3829,8 @@ public ListViewHitTestInfo HitTest(int x, int y)
{
if (lvhi.iSubItem < item.SubItems.Count)
{
return new ListViewHitTestInfo(item, item.SubItems[lvhi.iSubItem], location);
_listViewSubItem = item.SubItems[lvhi.iSubItem];
return new ListViewHitTestInfo(item, _listViewSubItem, location);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public override Rectangle Bounds
=> ParentInternal.GetChildInternal(ParentInternal.GetChildIndex(this) + 1),
UiaCore.NavigateDirection.PreviousSibling
=> ParentInternal.GetChildInternal(ParentInternal.GetChildIndex(this) - 1),
UiaCore.NavigateDirection.FirstChild => GetChild(),
UiaCore.NavigateDirection.LastChild => GetChild(),
_ => base.FragmentNavigate(direction)
};

Expand Down Expand Up @@ -161,6 +163,16 @@ internal override bool IsPatternSupported(UiaCore.UIA patternId)

private protected override string AutomationId
=> $"{nameof(ListViewSubItem)}-{ParentInternal.GetChildIndex(this)}";

private AccessibleObject? GetChild()
{
if (_owningListView._labelEdit is { } labelEdit)
{
return labelEdit.AccessibilityObject;
}

return null;
}
}
}
}
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.

using System.Drawing;
using static System.Windows.Forms.ListViewItem;
using static Interop;

namespace System.Windows.Forms;
Expand All @@ -11,29 +12,29 @@ internal class ListViewLabelEditAccessibleObject : AccessibleObject
private const string LIST_VIEW_LABEL_EDIT_AUTOMATION_ID = "1";

private readonly ListView _owningListView;
private readonly ListViewSubItem _owningListViewSubItem;
private readonly WeakReference<ListViewLabelEditNativeWindow> _labelEdit;
private readonly ListViewLabelEditUiaTextProvider _textProvider;
private int[]? _runtimeId;

public ListViewLabelEditAccessibleObject(ListView owningListView, ListViewLabelEditNativeWindow labelEdit)
{
_owningListView = owningListView.OrThrowIfNull();
_owningListViewSubItem = owningListView._listViewSubItem.OrThrowIfNull();
_labelEdit = new(labelEdit);
UseStdAccessibleObjects(labelEdit.Handle);
_textProvider = new ListViewLabelEditUiaTextProvider(owningListView, labelEdit, this);
}

private protected override string AutomationId => LIST_VIEW_LABEL_EDIT_AUTOMATION_ID;

public override AccessibleObject? Parent => _owningListViewSubItem.AccessibilityObject;

internal override UiaCore.IRawElementProviderFragment? FragmentNavigate(UiaCore.NavigateDirection direction)
{
AccessibleObject parent = _owningListView.AccessibilityObject;

return direction switch
{
UiaCore.NavigateDirection.Parent => parent,
UiaCore.NavigateDirection.NextSibling => parent.GetChildIndex(this) is int childId and >= 0 ? parent.GetChild(childId + 1) : null,
UiaCore.NavigateDirection.PreviousSibling => parent.GetChildIndex(this) is int childId and >= 0 ? parent.GetChild(childId - 1) : null,
UiaCore.NavigateDirection.Parent => Parent,
_ => base.FragmentNavigate(direction),
};
}
Expand Down
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.

using System.Drawing;
using static System.Windows.Forms.ListViewItem;
using static Interop;

namespace System.Windows.Forms.Tests;
Expand Down Expand Up @@ -49,11 +50,8 @@ public void ListViewLabelEditAccessibleObject_FragmentNavigate_ReturnsExpected()
ListViewLabelEditNativeWindow labelEdit = listView.TestAccessor().Dynamic._labelEdit;
ListViewLabelEditAccessibleObject accessibilityObject = (ListViewLabelEditAccessibleObject)labelEdit.AccessibilityObject;

Assert.Equal(listView.AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
Assert.Equal(listView.Items[0].AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.PreviousSibling));
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.NextSibling));
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.FirstChild));
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.LastChild));
Assert.Equal(listView._listViewSubItem.AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
Assert.NotNull(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
}

[WinFormsFact]
Expand Down Expand Up @@ -158,9 +156,11 @@ private ListView CreateListViewAndStartEditing()

listView.Columns.Add(new ColumnHeader() { Text = "Column 1", Width = 100 });

ListViewItem item = new("Test");
ListViewItem item = new("Test",0);
ListViewSubItem subItem = new ListViewSubItem(item, "Test");
item.SubItems.Add(subItem);
listView.Items.Add(item);

listView._listViewSubItem = subItem;
listView.CreateControl();

PInvoke.SetFocus(listView);
Expand Down