.NET version
.NET 10.0.11 (System.Windows.Forms.dll from Microsoft.WindowsDesktop.App\10.0.11), Windows 11 Pro 26100.
Did it work in .NET Framework?
Not applicable rather than not tested: the .NET Framework ListView has no UI Automation provider of its own, so clients use the built-in SysListView32 proxy and the defect cannot occur there.
Did it work in any of the earlier releases of .NET Core or .NET 5+?
Not bisected. The same behavior reproduces in a second, unrelated WinForms application on the same runtime, so it is not specific to one code base.
Issue description
A ListView in View.Details is exposed to UI Automation as ControlType.Table with the Grid and Table patterns, and every static piece of information is correct: row and column counts, column headers, and each cell's GridItemPattern / TableItemPattern row, column and header. But GridPattern.GetItem(row, column), the call a client makes to walk to a cell, returns elements with no control type and no name.
Measured with a UI Automation client against a four-column, three-row Details ListView (FullRowSelect = true, HideSelection = false, MultiSelect = false, no owner draw, no virtual mode, no image lists):
|
Stock WinForms ListView |
| Control type |
Table |
| Patterns advertised |
Selection, Grid, MultipleView, Table |
GridPattern.RowCount / ColumnCount |
3 × 4, correct |
TablePattern.GetColumnHeaders() |
Title, Position, Created, Modified, correct |
Each cell's GridItemPattern / TableItemPattern |
correct row, column and column header |
GridPattern.GetItem(row, column) |
empty, typeless elements |
The practical consequence is severe for screen-reader users. Because the control advertises a table, JAWS, NVDA and Narrator all enter their table handling, ask for a cell, get nothing usable back, and fall through to the row's Name, which is the first column only. All three readers read only the first column of a Details-mode ListView, with no way to reach the others. Verified by ear on all three.
The same control created as a raw Win32 SysListView32 (no WinForms, no in-process UIA provider) is read correctly by all three readers across every column, because they use their own SysListView32 handling via MSAA. Suppressing the WinForms UIA provider on the ListView (declining UiaRootObjectId in WM_GETOBJECT) restores the correct reading on all three as well, which is what we ship as a workaround.
So the provider advertises a capability it does not deliver, which is worse than not advertising it: a reader that believed the advertisement has abandoned the native handling that would have worked. Either GetItem should return the real cell elements (the ones that already answer GridItemPattern correctly), or the Grid/Table patterns should not be advertised.
Steps to reproduce
- WinForms app on
net10.0-windows, a form with one ListView { View = View.Details, FullRowSelect = true, HideSelection = false, MultiSelect = false, Dock = DockStyle.Fill }, four columns (Columns.Add("Title"), "Position", "Created", "Modified"), and three ListViewItems with four sub-items each.
- With a UI Automation client (Accessibility Insights, Inspect, or a few lines against
UIAutomationClient), find the list element. Observe ControlType.Table, GridPattern.RowCount = 3, ColumnCount = 4, correct column headers.
- Call
GridPattern.GetItem(0, 1). Expected: the element for the "Position" cell of row 0, with ControlType.Text (or DataItem) and the cell text as Name. Actual: an element with no control type and an empty name.
- Run JAWS, NVDA or Narrator and arrow through the rows. Expected: each row read across its columns. Actual: only the first column is read.
.NET version
.NET 10.0.11 (
System.Windows.Forms.dllfromMicrosoft.WindowsDesktop.App\10.0.11), Windows 11 Pro 26100.Did it work in .NET Framework?
Not applicable rather than not tested: the .NET Framework
ListViewhas no UI Automation provider of its own, so clients use the built-inSysListView32proxy and the defect cannot occur there.Did it work in any of the earlier releases of .NET Core or .NET 5+?
Not bisected. The same behavior reproduces in a second, unrelated WinForms application on the same runtime, so it is not specific to one code base.
Issue description
A
ListViewinView.Detailsis exposed to UI Automation asControlType.Tablewith the Grid and Table patterns, and every static piece of information is correct: row and column counts, column headers, and each cell'sGridItemPattern/TableItemPatternrow, column and header. ButGridPattern.GetItem(row, column), the call a client makes to walk to a cell, returns elements with no control type and no name.Measured with a UI Automation client against a four-column, three-row Details
ListView(FullRowSelect = true,HideSelection = false,MultiSelect = false, no owner draw, no virtual mode, no image lists):ListViewTableGridPattern.RowCount/ColumnCountTablePattern.GetColumnHeaders()GridItemPattern/TableItemPatternGridPattern.GetItem(row, column)The practical consequence is severe for screen-reader users. Because the control advertises a table, JAWS, NVDA and Narrator all enter their table handling, ask for a cell, get nothing usable back, and fall through to the row's
Name, which is the first column only. All three readers read only the first column of a Details-modeListView, with no way to reach the others. Verified by ear on all three.The same control created as a raw Win32
SysListView32(no WinForms, no in-process UIA provider) is read correctly by all three readers across every column, because they use their ownSysListView32handling via MSAA. Suppressing the WinForms UIA provider on theListView(decliningUiaRootObjectIdinWM_GETOBJECT) restores the correct reading on all three as well, which is what we ship as a workaround.So the provider advertises a capability it does not deliver, which is worse than not advertising it: a reader that believed the advertisement has abandoned the native handling that would have worked. Either
GetItemshould return the real cell elements (the ones that already answerGridItemPatterncorrectly), or the Grid/Table patterns should not be advertised.Steps to reproduce
net10.0-windows, a form with oneListView { View = View.Details, FullRowSelect = true, HideSelection = false, MultiSelect = false, Dock = DockStyle.Fill }, four columns (Columns.Add("Title"),"Position","Created","Modified"), and threeListViewItems with four sub-items each.UIAutomationClient), find the list element. ObserveControlType.Table,GridPattern.RowCount = 3,ColumnCount = 4, correct column headers.GridPattern.GetItem(0, 1). Expected: the element for the "Position" cell of row 0, withControlType.Text(orDataItem) and the cell text asName. Actual: an element with no control type and an empty name.