From 0ea693594ea618a1732c394c72d8e7b0c167fb9d Mon Sep 17 00:00:00 2001 From: JayashreeSF3546 Date: Wed, 15 Jul 2026 12:16:20 +0530 Subject: [PATCH 1/2] Arrow navigation always prioritizes parent DataGridView control regardless of what child control is focused. --- .../DataGridView/DataGridView.Methods.cs | 8 ++ .../System/Windows/Forms/DataGridViewTests.cs | 111 ++++++++++++++++++ 2 files changed, 119 insertions(+) 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..75ee012c06e 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) + { + 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); + } + } } From 992e3b99651a3c4d15dca8051916cd88205f3ee1 Mon Sep 17 00:00:00 2001 From: JayashreeSF3546 Date: Thu, 16 Jul 2026 15:32:03 +0530 Subject: [PATCH 2/2] extending the guard to also cover WM_CHAR --- .../Windows/Forms/Controls/DataGridView/DataGridView.Methods.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 75ee012c06e..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,7 +21929,7 @@ 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) + 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)) {