Skip to content

Commit f621c32

Browse files
SimonZhao888Simon Zhao (Beyondsoft Corporation) (from Dev Box)
andauthored
Make sure the Label Edit in ListView has correct position in accessibility tree (#9782)
* Adjusting the position of the LabelEdit in the accessibility tree * Update codes * Update code style and test cases * Add back the property of FragmentRoot * Update code style --------- Co-authored-by: Simon Zhao (Beyondsoft Corporation) (from Dev Box) <v-weidzh@microsoft.com>
1 parent e47bebd commit f621c32

File tree

5 files changed

+40
-38
lines changed

5 files changed

+40
-38
lines changed

src/System.Windows.Forms/src/System/Windows/Forms/ListView.ListViewAccessibleObject.cs

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,6 @@ internal override UiaCore.RowOrColumnMajor RowOrColumnMajor
9595
return null;
9696
}
9797

98-
if (owningListView._labelEdit is {} labelEdit && index == GetChildCount() - 1)
99-
{
100-
return labelEdit.AccessibilityObject;
101-
}
102-
10398
if (owningListView.GroupsDisplayed)
10499
{
105100
IReadOnlyList<ListViewGroup> visibleGroups = GetVisibleGroups();
@@ -117,10 +112,6 @@ public override int GetChildCount()
117112
}
118113

119114
int count = owningListView.GroupsDisplayed ? GetVisibleGroups().Count : owningListView.Items.Count;
120-
if (owningListView._labelEdit is not null)
121-
{
122-
count++;
123-
}
124115

125116
return count;
126117
}
@@ -167,9 +158,7 @@ internal override int GetChildIndex(AccessibleObject? child)
167158
return base.GetChildIndex(child);
168159
}
169160

170-
return owningListView._labelEdit is { } labelEdit && child == labelEdit.AccessibilityObject
171-
? GetChildCount() - 1
172-
: owningListView.GroupsDisplayed ? GetGroupIndex(child) : GetItemIndex(child);
161+
return owningListView.GroupsDisplayed ? GetGroupIndex(child) : GetItemIndex(child);
173162
}
174163

175164
private string GetItemStatus()
@@ -239,11 +228,6 @@ internal override string GetMultiViewProviderViewName(int viewId)
239228
return null;
240229
}
241230

242-
if (owningListView._labelEdit is {} labelEdit)
243-
{
244-
return labelEdit.AccessibilityObject;
245-
}
246-
247231
if (owningListView.GroupsDisplayed)
248232
{
249233
IReadOnlyList<ListViewGroup> visibleGroups = GetVisibleGroups();

src/System.Windows.Forms/src/System/Windows/Forms/ListView.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Windows.Forms.VisualStyles;
1313
using Windows.Win32.UI.Input.KeyboardAndMouse;
1414
using static System.Windows.Forms.ListViewGroup;
15+
using static System.Windows.Forms.ListViewItem;
1516
using static Interop;
1617
using static Interop.ComCtl32;
1718

@@ -175,7 +176,10 @@ public partial class ListView : Control
175176

176177
private bool _blockLabelEdit;
177178

178-
private ListViewLabelEditNativeWindow? _labelEdit;
179+
internal ListViewLabelEditNativeWindow? _labelEdit;
180+
181+
// Used to record the SubItem to which the Label Edit belongs.
182+
internal ListViewSubItem? _listViewSubItem;
179183

180184
// Background image stuff
181185
// Because we have to create a temporary file and the OS does not clean up the temporary files from the machine
@@ -3394,24 +3398,24 @@ public void EnsureVisible(int index)
33943398
// win32 listView control can't search inside sub items
33953399
for (int i = startIndex; i < Items.Count; i++)
33963400
{
3397-
ListViewItem lvi = Items[i];
3398-
for (int j = 0; j < lvi.SubItems.Count; j++)
3401+
ListViewItem listViewItem = Items[i];
3402+
for (int j = 0; j < listViewItem.SubItems.Count; j++)
33993403
{
3400-
ListViewItem.ListViewSubItem lvsi = lvi.SubItems[j];
3404+
ListViewSubItem listViewSubItem = listViewItem.SubItems[j];
34013405
// the win32 list view search for items w/ text is case insensitive
34023406
// do the same for sub items
34033407
// because we are comparing user defined strings we have to do the slower String search
34043408
// ie, use String.Compare(string, string, case sensitive, CultureInfo)
34053409
// instead of new Whidbey String.Equals overload
34063410
// String.Equals(string, string, StringComparison.OrdinalIgnoreCase
3407-
if (string.Equals(text, lvsi.Text, StringComparison.OrdinalIgnoreCase))
3411+
if (string.Equals(text, listViewSubItem.Text, StringComparison.OrdinalIgnoreCase))
34083412
{
3409-
return lvi;
3413+
return listViewItem;
34103414
}
34113415

3412-
if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(lvsi.Text, text, CompareOptions.IgnoreCase))
3416+
if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(listViewSubItem.Text, text, CompareOptions.IgnoreCase))
34133417
{
3414-
return lvi;
3418+
return listViewItem;
34153419
}
34163420
}
34173421
}
@@ -3825,7 +3829,8 @@ public ListViewHitTestInfo HitTest(int x, int y)
38253829
{
38263830
if (lvhi.iSubItem < item.SubItems.Count)
38273831
{
3828-
return new ListViewHitTestInfo(item, item.SubItems[lvhi.iSubItem], location);
3832+
_listViewSubItem = item.SubItems[lvhi.iSubItem];
3833+
return new ListViewHitTestInfo(item, _listViewSubItem, location);
38293834
}
38303835
else
38313836
{

src/System.Windows.Forms/src/System/Windows/Forms/ListViewItem.ListViewSubItem.ListViewSubItemAccessibleObject.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ public override Rectangle Bounds
7676
=> ParentInternal.GetChildInternal(ParentInternal.GetChildIndex(this) + 1),
7777
UiaCore.NavigateDirection.PreviousSibling
7878
=> ParentInternal.GetChildInternal(ParentInternal.GetChildIndex(this) - 1),
79+
UiaCore.NavigateDirection.FirstChild => GetChild(),
80+
UiaCore.NavigateDirection.LastChild => GetChild(),
7981
_ => base.FragmentNavigate(direction)
8082
};
8183

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

162164
private protected override string AutomationId
163165
=> $"{nameof(ListViewSubItem)}-{ParentInternal.GetChildIndex(this)}";
166+
167+
private AccessibleObject? GetChild()
168+
{
169+
if (_owningListView._labelEdit is { } labelEdit)
170+
{
171+
return labelEdit.AccessibilityObject;
172+
}
173+
174+
return null;
175+
}
164176
}
165177
}
166178
}

src/System.Windows.Forms/src/System/Windows/Forms/ListViewLabelEditAccessibleObject.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Drawing;
5+
using static System.Windows.Forms.ListViewItem;
56
using static Interop;
67

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

1314
private readonly ListView _owningListView;
15+
private readonly ListViewSubItem _owningListViewSubItem;
1416
private readonly WeakReference<ListViewLabelEditNativeWindow> _labelEdit;
1517
private readonly ListViewLabelEditUiaTextProvider _textProvider;
1618
private int[]? _runtimeId;
1719

1820
public ListViewLabelEditAccessibleObject(ListView owningListView, ListViewLabelEditNativeWindow labelEdit)
1921
{
2022
_owningListView = owningListView.OrThrowIfNull();
23+
_owningListViewSubItem = owningListView._listViewSubItem.OrThrowIfNull();
2124
_labelEdit = new(labelEdit);
2225
UseStdAccessibleObjects(labelEdit.Handle);
2326
_textProvider = new ListViewLabelEditUiaTextProvider(owningListView, labelEdit, this);
2427
}
2528

2629
private protected override string AutomationId => LIST_VIEW_LABEL_EDIT_AUTOMATION_ID;
2730

31+
public override AccessibleObject? Parent => _owningListViewSubItem.AccessibilityObject;
32+
2833
internal override UiaCore.IRawElementProviderFragment? FragmentNavigate(UiaCore.NavigateDirection direction)
2934
{
30-
AccessibleObject parent = _owningListView.AccessibilityObject;
31-
3235
return direction switch
3336
{
34-
UiaCore.NavigateDirection.Parent => parent,
35-
UiaCore.NavigateDirection.NextSibling => parent.GetChildIndex(this) is int childId and >= 0 ? parent.GetChild(childId + 1) : null,
36-
UiaCore.NavigateDirection.PreviousSibling => parent.GetChildIndex(this) is int childId and >= 0 ? parent.GetChild(childId - 1) : null,
37+
UiaCore.NavigateDirection.Parent => Parent,
3738
_ => base.FragmentNavigate(direction),
3839
};
3940
}

src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListViewLabelEditAccessibleObjectTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Drawing;
5+
using static System.Windows.Forms.ListViewItem;
56
using static Interop;
67

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

52-
Assert.Equal(listView.AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
53-
Assert.Equal(listView.Items[0].AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.PreviousSibling));
54-
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.NextSibling));
55-
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.FirstChild));
56-
Assert.Null(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.LastChild));
53+
Assert.Equal(listView._listViewSubItem.AccessibilityObject, accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
54+
Assert.NotNull(accessibilityObject.FragmentNavigate(UiaCore.NavigateDirection.Parent));
5755
}
5856

5957
[WinFormsFact]
@@ -158,9 +156,11 @@ private ListView CreateListViewAndStartEditing()
158156

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

161-
ListViewItem item = new("Test");
159+
ListViewItem item = new("Test",0);
160+
ListViewSubItem subItem = new ListViewSubItem(item, "Test");
161+
item.SubItems.Add(subItem);
162162
listView.Items.Add(item);
163-
163+
listView._listViewSubItem = subItem;
164164
listView.CreateControl();
165165

166166
PInvoke.SetFocus(listView);

0 commit comments

Comments
 (0)