.NET version
.NET 10 (10.0.11). Same code in main. The behaviour is also there in .NET 9.
Did it work in .NET Framework?
No. I built the same repro for .NET Framework 4.8: NVDA 2026.2.0 is silent on opening there too, and no item is selected. (With the arrows it then says "DropDown toolbar, Open", without the position; on .NET the items are read better, "Open, 1 of 4".) The MSAA events on 4.8 are MENUPOPUPSTART name="DropDown" role=MENUPOPUP on opening and no FOCUS until an arrow key is pressed. So this is a long-standing gap, not a regression.
Did it work in any of the earlier releases of .NET Core or .NET 5+?
No. #3334 reported it for .NET Core 3.1; it was closed as an NVDA problem after checking that the UIA tree was correct. The tree is correct; the problem is in the events.
Issue description
Open a ContextMenuStrip with Shift+F10 or the Applications key (the menu is just assigned to Control.ContextMenuStrip). With NVDA nothing is announced until an arrow key is pressed. I am a blind developer and I hit this in my own app, so I listened to the UIA and MSAA events from another process and read the source. There are three separate causes:
-
MenuOpened is not raised the first time the menu opens. ContextMenuStrip.OnOpened only raises UIA_MenuOpenedEventId when IsAccessibilityObjectCreated is true. The first time a context menu opens nothing has asked for its accessible object yet: it has no owner item and it was never part of the tree a client walked. From the second opening on, the event is raised.
-
No item is selected, so nothing gets the accessibility focus. ContextMenuStrip.ShowInternal(source, location, isKeyboardActivated) only turns the mnemonic underlines on. A submenu opened from the keyboard selects its first item (ToolStripMenuItem calls DropDown.SelectNextToolStripItem(start: null, forward: true)), and so does a native Windows menu opened from the keyboard: for the system menu the WinEvents are MENUPOPUPSTART followed at once by FOCUS on "Restore".
-
The focus event of an item can be skipped in a context menu. ToolStripItem.Select decides whether accessibility is on with:
IsOnDropDown ? OwnerItem?.IsAccessibilityObjectCreated ?? false : IsParentAccessibilityObjectCreated
The items of a ContextMenuStrip are on a drop-down that has no OwnerItem, so this is always false unless the item's own accessible object already exists.
A related point: the menu has no accessible name, because ToolStripDropDownAccessibleObject.Name takes it from the owner item and a context menu has none. On .NET Framework 4.8 it was named "DropDown". Native context menus are named "Context", which screen readers announce followed by the role ("Context menu").
Measurements: the UIA events seen from another process, before and after
Stock .NET 10.0.11. First opening with Shift+F10, then Down, Down:
(nothing on opening)
FocusChanged: MenuItem "Open" <- only after pressing Down
FocusChanged: MenuItem "Edit"
MenuClosed: Menu ""
With the proposed changes:
MenuOpened: Menu "Context"
FocusChanged: MenuItem "Open" <- on opening
FocusChanged: MenuItem "Edit" <- Down
What screen readers say with the proposed changes
That is the same experience the readers give with the other WinForms menus on .NET: Alt+F on a MenuStrip, where the first item has always been selected at once, gives "New, 1 of 3" in NVDA and in JAWS, and neither says "menu". They announce the focused item rather than the menu because its focus event follows MenuOpened at once; that is a matter for the readers (for NVDA I traced it to MenuOpened being dropped when the menu does not report HasKeyboardFocus, and I will report it there), not something the menu should work around.
Steps to reproduce
Button button = new() { Text = "Button with a ContextMenuStrip", AutoSize = true };
ContextMenuStrip menu = new();
menu.Items.Add("&Open");
menu.Items.Add("&Edit");
button.ContextMenuStrip = menu;
Controls.Add(button);
- Run it with NVDA. Focus the button and press Shift+F10.
- Nothing is announced. Press Down: "Open, 1 of 2".
I have the changes with unit tests ready and will open a pull request.
A draft pull request with the changes is open alongside this issue, in case it helps to judge the direction; I am happy to adjust it.
.NET version
.NET 10 (10.0.11). Same code in
main. The behaviour is also there in .NET 9.Did it work in .NET Framework?
No. I built the same repro for .NET Framework 4.8: NVDA 2026.2.0 is silent on opening there too, and no item is selected. (With the arrows it then says "DropDown toolbar, Open", without the position; on .NET the items are read better, "Open, 1 of 4".) The MSAA events on 4.8 are
MENUPOPUPSTART name="DropDown" role=MENUPOPUPon opening and noFOCUSuntil an arrow key is pressed. So this is a long-standing gap, not a regression.Did it work in any of the earlier releases of .NET Core or .NET 5+?
No. #3334 reported it for .NET Core 3.1; it was closed as an NVDA problem after checking that the UIA tree was correct. The tree is correct; the problem is in the events.
Issue description
Open a
ContextMenuStripwith Shift+F10 or the Applications key (the menu is just assigned toControl.ContextMenuStrip). With NVDA nothing is announced until an arrow key is pressed. I am a blind developer and I hit this in my own app, so I listened to the UIA and MSAA events from another process and read the source. There are three separate causes:MenuOpenedis not raised the first time the menu opens.ContextMenuStrip.OnOpenedonly raisesUIA_MenuOpenedEventIdwhenIsAccessibilityObjectCreatedis true. The first time a context menu opens nothing has asked for its accessible object yet: it has no owner item and it was never part of the tree a client walked. From the second opening on, the event is raised.No item is selected, so nothing gets the accessibility focus.
ContextMenuStrip.ShowInternal(source, location, isKeyboardActivated)only turns the mnemonic underlines on. A submenu opened from the keyboard selects its first item (ToolStripMenuItemcallsDropDown.SelectNextToolStripItem(start: null, forward: true)), and so does a native Windows menu opened from the keyboard: for the system menu the WinEvents areMENUPOPUPSTARTfollowed at once byFOCUSon "Restore".The focus event of an item can be skipped in a context menu.
ToolStripItem.Selectdecides whether accessibility is on with:The items of a
ContextMenuStripare on a drop-down that has noOwnerItem, so this is alwaysfalseunless the item's own accessible object already exists.A related point: the menu has no accessible name, because
ToolStripDropDownAccessibleObject.Nametakes it from the owner item and a context menu has none. On .NET Framework 4.8 it was named "DropDown". Native context menus are named "Context", which screen readers announce followed by the role ("Context menu").Measurements: the UIA events seen from another process, before and after
Stock .NET 10.0.11. First opening with Shift+F10, then Down, Down:
With the proposed changes:
What screen readers say with the proposed changes
NoClientNotificationscheck inControl.AccessibilityNotifyClients) #15176; without it JAWS reads the items erratically.)That is the same experience the readers give with the other WinForms menus on .NET: Alt+F on a
MenuStrip, where the first item has always been selected at once, gives "New, 1 of 3" in NVDA and in JAWS, and neither says "menu". They announce the focused item rather than the menu because its focus event followsMenuOpenedat once; that is a matter for the readers (for NVDA I traced it toMenuOpenedbeing dropped when the menu does not reportHasKeyboardFocus, and I will report it there), not something the menu should work around.Steps to reproduce
I have the changes with unit tests ready and will open a pull request.
A draft pull request with the changes is open alongside this issue, in case it helps to judge the direction; I am happy to adjust it.