Skip to content

Commit ecc65f0

Browse files
authored
[release/9.0][Accessibility] Fix keyboard navigation and screen reader experience in dropdown type editors in property grid (#12605)
Backport of #12508, #12431, #12356 and #12479 to release/9.0 Fixes #12607 NET10 Bugs: #12434, #12421, #12440, #12031 Bug Description There are four issues that occur when using the up/down keys to switch property values ​​in the property page. When navigating to "Auto Size" dropdown using the up/down arrow keys, it is getting auto selected without hitting ENTER After using Tab to switch property values, then using the up/down keys to switch items in the drop-down box expanded by F4 will cause the drop-down box to collapse directly [Accessibility] When using up/down to toggle property value on edit text box, The Accessibility ​​rectangle focuses on the entire property row instead of the original edit text box [Accessibility] Narrator cannot announce items correctly when switching the items by using up/down keyboard arrow that without expand the dropdown list panel Customer Impact PropertyGrid drop down type editor does not support conventional keyboard navigation. Usually, selection is committed when the ENTER key is pressed. However, in this case value is committed on the Down arrow press. Then the drop down list is expanded, the screen reader user might want to navigate through all values in the drop down using the arrows, on each arrow key press the new item should be presented (and announced) in the selection text box, however, the drop down is closed on the first arrow key. According to the accessibility SMEs, this is a major problem - the keyboard users are losing their work by committing a wrong value. Screen reader user don't get correct feedback when navigating through the drop down list.
1 parent 87c7908 commit ecc65f0

File tree

3 files changed

+35
-23
lines changed

3 files changed

+35
-23
lines changed

src/System.Windows.Forms/src/System/Windows/Forms/Controls/PropertyGrid/PropertyGridInternal/PropertyGridView.cs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2475,7 +2475,8 @@ private bool ProcessEnumUpAndDown(GridEntry entry, Keys keyCode, bool closeDropD
24752475
}
24762476

24772477
CommitValue(entry, valueNew, closeDropDown);
2478-
EditTextBox?.SelectAll();
2478+
EditTextBox.HookMouseDown = false;
2479+
EditTextBox.SelectAll();
24792480
return true;
24802481
}
24812482

@@ -3997,7 +3998,7 @@ private void Refresh(bool fullRefresh, int startRow, int endRow)
39973998
startRow = 0;
39983999
}
39994000

4000-
if (fullRefresh || OwnerGrid.HavePropertyEntriesChanged())
4001+
if (OwnerGrid.HavePropertyEntriesChanged())
40014002
{
40024003
if (HasEntries && !InPropertySet && !CommitEditTextBox())
40034004
{
@@ -4018,7 +4019,10 @@ private void Refresh(bool fullRefresh, int startRow, int endRow)
40184019
if (oldLength > 0 && !_flags.HasFlag(Flags.NoDefault))
40194020
{
40204021
_positionData = CaptureGridPositionData();
4021-
CommonEditorHide(true);
4022+
if (!fullRefresh)
4023+
{
4024+
CommonEditorHide(true);
4025+
}
40224026
}
40234027

40244028
UpdateHelpAttributes(_selectedGridEntry, newEntry: null);
@@ -4299,17 +4303,10 @@ private void SelectRow(int row)
42994303
return;
43004304
}
43014305

4302-
bool newRow = false;
43034306
int oldSelectedRow = _selectedRow;
4304-
if (_selectedRow != row || !gridEntry.Equals(_selectedGridEntry))
4307+
if (_selectedRow != row || (_selectedGridEntry is not null && !gridEntry.Equals(_selectedGridEntry)))
43054308
{
43064309
CommonEditorHide();
4307-
newRow = true;
4308-
}
4309-
4310-
if (!newRow)
4311-
{
4312-
CloseDropDown();
43134310
}
43144311

43154312
Rectangle rect = GetRectangle(row, RowValue);
@@ -4400,7 +4397,7 @@ private void SelectRow(int row)
44004397
_selectedGridEntry.HasFocus = FocusInside;
44014398
}
44024399

4403-
if (!_flags.HasFlag(Flags.IsNewSelection))
4400+
if (!_flags.HasFlag(Flags.IsNewSelection) && !_flags.HasFlag(Flags.InPropertySet))
44044401
{
44054402
Focus();
44064403
}

src/System.Windows.Forms/src/System/Windows/Forms/Controls/TextBox/TextBoxBase.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,26 +1730,28 @@ public void Select(int start, int length)
17301730
/// But if you do have it cached, please pass it in. This will avoid
17311731
/// the expensive call to the TextLength property.
17321732
/// </summary>
1733-
private protected virtual void SelectInternal(int start, int length, int textLen)
1733+
private protected virtual void SelectInternal(int selectionStart, int selectionLength, int textLength)
17341734
{
17351735
// if our handle is created - send message...
17361736
if (IsHandleCreated)
17371737
{
1738-
AdjustSelectionStartAndEnd(start, length, out int s, out int e, textLen);
1738+
AdjustSelectionStartAndEnd(selectionStart, selectionLength, out int start, out int end, textLength);
17391739

1740-
PInvoke.SendMessage(this, PInvoke.EM_SETSEL, (WPARAM)s, (LPARAM)e);
1740+
PInvoke.SendMessage(this, PInvoke.EM_SETSEL, (WPARAM)start, (LPARAM)end);
17411741

17421742
if (IsAccessibilityObjectCreated)
17431743
{
1744-
AccessibilityObject.RaiseAutomationEvent(UIA_EVENT_ID.UIA_Text_TextSelectionChangedEventId);
1744+
AccessibilityObject.RaiseAutomationEvent(end == 0
1745+
? UIA_EVENT_ID.UIA_AutomationFocusChangedEventId
1746+
: UIA_EVENT_ID.UIA_Text_TextSelectionChangedEventId);
17451747
}
17461748
}
17471749
else
17481750
{
17491751
// otherwise, wait until handle is created to send this message.
17501752
// Store the indices until then...
1751-
_selectionStart = start;
1752-
_selectionLength = length;
1753+
_selectionStart = selectionStart;
1754+
_selectionLength = selectionLength;
17531755
_textBoxFlags[s_setSelectionOnHandleCreated] = true;
17541756
}
17551757
}

src/System.Windows.Forms/tests/IntegrationTests/DesignSurface/DemoConsole/MainForm.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,22 +118,35 @@ private void CreateDesignSurface(int n)
118118
// - create some Controls at DesignTime
119119
TextBox t1 = surface.CreateControl<TextBox>(new Size(200, 23), new Point(172, 12));
120120
Button b1 = surface.CreateControl<Button>(new Size(200, 40), new Point(172, 63));
121-
CustomButton b2 = surface.CreateControl<CustomButton>(new Size(200, 40), new Point(100, 200));
121+
CustomButton b2 = surface.CreateControl<CustomButton>(new Size(200, 40), new Point(172, 200));
122122
b1.Text = "I'm the first Button";
123123
b2.Text = "I'm the second Button";
124124
b1.BackColor = Color.LightGray;
125125
b2.BackColor = Color.LightGreen;
126126

127-
RadioButton rb1 = surface.CreateControl<RadioButton>(new Size(120, 22), new Point(12, 21));
127+
RadioButton rb1 = surface.CreateControl<RadioButton>(new Size(120, 22), new Point(12, 10));
128128
rb1.Text = "Check me!";
129-
RadioButton rb2 = surface.CreateControl<RadioButton>(new Size(120, 22), new Point(12, 50));
129+
RadioButton rb2 = surface.CreateControl<RadioButton>(new Size(120, 22), new Point(12, 35));
130130
rb2.Text = "No, check me!";
131131
rb2.Checked = true;
132132

133-
Panel pnl = surface.CreateControl<Panel>(new Size(130, 100), new Point(12, 21));
133+
CheckBox checkbox1 = surface.CreateControl<CheckBox>(new Size(120, 22), new Point(12, 60));
134+
checkbox1.Text = "I'm Unchecked!";
135+
CheckBox checkbox2 = surface.CreateControl<CheckBox>(new Size(120, 22), new Point(12, 85));
136+
checkbox2.Text = "I'm Indeterminate!";
137+
checkbox2.AutoSize = true;
138+
checkbox2.CheckState = CheckState.Indeterminate;
139+
CheckBox checkbox3 = surface.CreateControl<CheckBox>(new Size(120, 22), new Point(12, 110));
140+
checkbox3.Text = "I'm Checked!";
141+
checkbox3.CheckState = CheckState.Checked;
142+
143+
Panel pnl = surface.CreateControl<Panel>(new Size(140, 140), new Point(12, 12));
134144
pnl.BackColor = Color.Aquamarine;
135145
rb1.Parent = pnl;
136146
rb2.Parent = pnl;
147+
checkbox1.Parent = pnl;
148+
checkbox2.Parent = pnl;
149+
checkbox3.Parent = pnl;
137150

138151
Label l1 = surface.CreateControl<Label>(new Size(100, 25), new Point(12, 12));
139152
Label l2 = surface.CreateControl<Label>(new Size(120, 25), new Point(12, 12));
@@ -148,7 +161,7 @@ private void CreateDesignSurface(int n)
148161
l1.Parent = sct.Panel1;
149162
l2.Parent = sct.Panel2;
150163

151-
PictureBox pb1 = surface.CreateControl<PictureBox>(new Size(64, 64), new Point(24, 166));
164+
PictureBox pb1 = surface.CreateControl<PictureBox>(new Size(64, 64), new Point(12, 176));
152165
pb1.Image = new Icon("painter.ico").ToBitmap();
153166

154167
ContextMenuStrip cm1 = surface.CreateComponent<ContextMenuStrip>();

0 commit comments

Comments
 (0)