dotnet / dotnet/winforms

Details-mode ListView advertises GridPattern but GetItem(row, column) returns empty elements, so JAWS, NVDA and Narrator read only the first column

Open
#15,044 0 comments 0 reactions 1 assignee Claimed by @LeafShi1 View on GitHub
Dominant language
C#
Stars
4.9k
Forks
1.1k
Avg merge
20h 23m
Merged PRs (30d)
103

Description

### .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

1. 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 `ListViewItem`s with four sub-items each.
2. 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.
3. 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.
4. Run JAWS, NVDA or Narrator and arrow through the rows. Expected: each row read across its columns. Actual: only the first column is read.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.