diff --git a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs index c48810dbc1a..96c7132eb7e 100644 --- a/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs +++ b/src/System.Windows.Forms/System/Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs @@ -21929,6 +21929,14 @@ protected override bool ProcessKeyEventArgs(ref Message m) protected override bool ProcessKeyPreview(ref Message m) { + if (m.MsgInternal == PInvokeCore.WM_KEYDOWN || m.MsgInternal == PInvokeCore.WM_SYSKEYDOWN || m.MsgInternal == PInvokeCore.WM_CHAR) + { + if (m.HWND != HWND && (EditingControl is null || m.HWND != EditingControl.HWND)) + { + return base.ProcessKeyPreview(ref m); + } + } + bool dataGridViewWantsInputKey; KeyEventArgs ke = new((Keys)(nint)m.WParamInternal | ModifierKeys); diff --git a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewTests.cs b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewTests.cs index 51e5f9b4b98..d79cca0216b 100644 --- a/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewTests.cs +++ b/src/test/unit/System.Windows.Forms/System/Windows/Forms/DataGridViewTests.cs @@ -4084,4 +4084,115 @@ public void DataGridView_Dispose_KeyboardToolTip_Disposed() dataGridView.Dispose(); toolTipDisposeCount.Should().Be(1); } + + [WinFormsFact] + public void ProcessKeyPreview_HostedChild_ArrowKey_DoesNotRouteToDataGridView() + { + using Form form = new(); + using TestDataGridView dataGridView = CreateGrid(); + using TextBox hostedTextBox = new(); + + form.Controls.Add(dataGridView); + dataGridView.Controls.Add(hostedTextBox); + + form.Show(); + dataGridView.CreateControl(); + hostedTextBox.CreateControl(); + hostedTextBox.Focus(); + + dataGridView.CurrentCell = dataGridView[0, 0]; + + Message message = Message.Create( + hostedTextBox.Handle, + (int)PInvokeCore.WM_KEYDOWN, + (IntPtr)Keys.Down, + IntPtr.Zero); + + dataGridView.CallProcessKeyPreview(ref message); + + Assert.False(dataGridView.ProcessDataGridViewKeyCalled); + Assert.Equal(0, dataGridView.CurrentCell.RowIndex); + } + + [WinFormsFact] + public void ProcessKeyPreview_DataGridViewTarget_ArrowKey_StillRoutesToDataGridView() + { + using Form form = new(); + using TestDataGridView dataGridView = CreateGrid(); + + form.Controls.Add(dataGridView); + form.Show(); + dataGridView.CreateControl(); + dataGridView.Focus(); + + dataGridView.CurrentCell = dataGridView[0, 0]; + + Message message = Message.Create( + dataGridView.Handle, + (int)PInvokeCore.WM_KEYDOWN, + (IntPtr)Keys.Down, + IntPtr.Zero); + + dataGridView.CallProcessKeyPreview(ref message); + + Assert.True(dataGridView.ProcessDataGridViewKeyCalled); + } + + [WinFormsFact] + public void ProcessKeyPreview_HostedChild_NonArrowKey_DoesNotUseArrowSuppression() + { + using Form form = new(); + using TestDataGridView dataGridView = CreateGrid(); + using TextBox hostedTextBox = new(); + + form.Controls.Add(dataGridView); + dataGridView.Controls.Add(hostedTextBox); + + form.Show(); + dataGridView.CreateControl(); + hostedTextBox.CreateControl(); + hostedTextBox.Focus(); + + Message message = Message.Create( + hostedTextBox.Handle, + (int)PInvokeCore.WM_KEYDOWN, + (IntPtr)Keys.Enter, + IntPtr.Zero); + + dataGridView.CallProcessKeyPreview(ref message); + + // This test is weaker than the arrow-key tests, but still verifies + // that the arrow-specific logic is not applied to Enter. + Assert.False(dataGridView.ProcessDataGridViewKeyCalled); + } + + private static TestDataGridView CreateGrid() + { + TestDataGridView grid = new() + { + Width = 300, + Height = 200 + }; + + grid.Columns.Add("Col1", "Col1"); + grid.Columns.Add("Col2", "Col2"); + grid.Rows.Add("A1", "B1"); + grid.Rows.Add("A2", "B2"); + + return grid; + } + + private sealed class TestDataGridView : DataGridView + { + public bool ProcessDataGridViewKeyCalled { get; private set; } + + public bool CallProcessKeyPreview(ref Message m) + => ProcessKeyPreview(ref m); + + protected override bool ProcessDataGridViewKey(KeyEventArgs e) + { + ProcessDataGridViewKeyCalled = true; + return base.ProcessDataGridViewKey(e); + } + } }