很难描述这个问题。让我用一个非常简单的例子来说明。从winform(.net framework 4.8(的新解决方案开始。添加一个带有文本框的菜单条,然后添加一个数据网格视图。让我们来处理datagridview的KeyDown事件。
if (e.KeyCode == Keys.F3)
toolStripTextBox1.Focus();
好的,现在我们开始这个程序。
- 单击数据网格视图以关注它
- 单击文本框以更改焦点
- 按键盘上的Esc键
您可以看到datagridview获得了预期的焦点。
但是,如果你在第二步做一点改变,结果会令人困惑。按F3而不是单击文本框。这次按Esc键时,焦点会丢失。我试着打印名称和焦点控制的句柄。原来是文本框本身。有人能解释一下吗?
现在我很确定这是某种bug。在吉米提到hwndThatLostFocus
之后,我追踪了这个变量好几个小时。虽然我没有找到hwndThatLostFocus
更改的确切位置,但发现了一些不合理的地方:当在不同情况下调用Focus()
时,结果失去了一致性。
在大多数情况下,如果调用ToolStripTextBox的Focus()
,则ToolStripTextBox的hwndThatLostFocus
将设置为0,就像我问题中的示例一样。但是,如果您单击数据网格视图并单击ToolStripTextBox,然后单击数据网格查看agian,那么这次调用Focus()
时,hwndThatLostFocus
将仍然是指向数据网格视图的指针。此外,这一点可在.net 6中转载。
稍后我将向Microsoft报告此情况。目前,有三种方法可以避免这种情况。
-
通过
user32.dll
中的SetCursorPos
和mouse_event
模拟鼠标单击。 -
像吉米的建议一样进行反思。
-
在
Form
中覆盖ProcessCmdKey
,自己照顾Keys.Escape
:protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { if (keyData == Keys.Escape && msg.HWnd == toolStripTextBox1.TextBox.Handle) { dataGridView1.Focus(); return true; } return base.ProcessCmdKey(ref msg, keyData); }
因为我避免使用不必要的反射,而且Dllimport对我来说也有点难看,所以我更喜欢第三种。