- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我本来是想让我的程序获取箭头键(上,下,左和右)的输入,但是却发现在KeyDown()中这些键从未使用过的困难方式。之后,我发现可以通过进入PreviewKeyDown()函数并进行设置来启用箭头键:
e.IsInputKey = true;
private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{ /*whatever logic goes here*/}
this.Focus()
最佳答案
为什么
您可以尝试这个小实验:用两个按钮创建一个表单,覆盖PreviewKeyDown()
,设置一个断点,运行它,然后按左/右箭头键。 PreviewKeyDown()
方法将不会运行。但是删除按钮,将调用覆盖。
造成这种差异的原因是WinForms本身正在处理箭头键以进行导航。当您拥有按钮和文本框之类的输入控件时,WinForms将自动接管某些特殊键,例如TAB
和箭头键,以从一个控件导航到下一个控件。之所以这样做,是因为很多人都希望能够使用键盘进行导航,如果您弄乱了导航键,很容易为他们打破这一点。最好为您处理它们,以免在您玩其他键时将它们弄乱。
一个幼稚的解决方法是检测表单何时失去焦点并将其收回。但是,这不起作用,因为您的表单不会失去焦点。输入控件具有焦点,它们是表单的一部分,因此表单仍(在技术上,间接地)具有焦点。只有在其他窗口上单击外部时,它才会失去焦点。
更好的解决方法是对.Net解释器正下方的“幕后”进行更好的理解。 WinForms非常接近地模拟了此级别,因此它是了解WinForms的有用指南。
当Windows将输入(例如击键)发送到程序时,您的窗体并不总是第一个获取输入的窗体。输入将转到具有焦点的任何控件。在这种情况下,该控件是其中一个按钮(我假设首先隐藏了焦点发光,以证明为什么当看起来什么都没有选择时在第一笔划中什么也没有发生)。
一旦按钮掌握了输入,就可以决定下一步将发生什么。它可以将输入传递给下一个排队的人,先执行某项操作然后传递给它,或者完全处理输入而不传递任何输入。
使用普通的字母键,按钮会决定它不知道如何处理它们,而是将其传递给其基类。基类也不知道,因此它转发 key 。最终,它命中了Control
类,该类通过将其传递给Control
属性中的任何Parent
进行处理。如果进行的时间足够长,您的表单最终将有机会处理输入。
简而言之,WinForms首先将输入提供给最特定的目标,然后解决越来越多的一般问题,直到有人知道如何处理输入。
但是,对于箭头键,按钮知道如何处理。它通过将焦点传递到下一个输入控件来处理它们。此时,该按钮声明输入已完全处理,吞下了该键,并且没有给其他任何机会查看它的机会。按下按钮后甚至没人知道按键曾经发生过。
这就是为什么您的PreviewKeyDown()
覆盖没有被调用的原因。仅当Form
获得击键时才调用它,但是由于它进入了输入控件,提供了让导航代码查看它的输入控件,并吞没了它,因此它从未获得击键。
解决方法
不幸的是,解决这个问题将是一项工作。击键已消失在输入控件中,因此您需要使所有输入控件都与将箭头键输入到窗体中有关。
为此,您需要从使用的所有输入控件类型中派生新控件,并使用它们代替原始控件。然后,您必须重写每个方法中的OnPreviewKeyDown()
方法并设置e.IsInputKey = true
。这样会将您的箭头键放到派生控件的KeyDown()
处理程序中,而不是让它们被导航代码偷走。
接下来,您还必须在所有这些控件中处理KeyDown()
事件。由于您希望箭头键引发Form
中的事件,因此所有派生的控件都需要跟踪其窗体并将这些键传递给该控件(这意味着窗体的方法将需要公开)。
将所有内容放在一起,箭头键传递的输入控件将看起来像这样。
class MyButton : Button
{
public MyButton()
{
this.KeyDown += new KeyEventHandler(MyButton_KeyDown);
}
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
e.IsInputKey = true;
base.OnPreviewKeyDown(e);
}
private void MyButton_KeyDown(object sender, KeyEventArgs e)
{
Form1 f = (Form1)this.FindForm();
f.Form1_KeyDown(sender, e);
}
}
ProcessCmdKey()
方法并在那里处理键。这样的事情可能会起作用:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Up || keyData == Keys.Down ||
keyData == Keys.Left || keyData == Keys.Right)
{
object sender = Control.FromHandle(msg.HWnd);
KeyEventArgs e = new KeyEventArgs(keyData);
Form1_KeyPress(sender, e);
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}
PreviewKeyDown()
并设置
e.IsInputKey = true
。将首先使用 child 的
PreviewKeyDown()
方法,然后将箭头视为不是命令键,并且不会调用您的
ProcessCmdKey()
。
ProcessCmdKey()
是
context menu handling的意思。我不确定将其用于上下文菜单以外的其他选项是否明智,但是
even Microsoft recommends it for similar kinds of use确实有效,因此可能值得考虑。
关于c# - 在Winforms中,从不为任何键触发PreviewKeyDown(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25696507/
这个问题已经有答案了: jQuery trigger click vs click ()? (3 个回答) 已关闭 5 年前。 我无法区分 trigger('click')与 trigger('cli
我正在运行 VS 2008 和 .NET 3.5 SP1。 我想在 HttpModule 中实现命中跟踪在我的 ASP.NET 应用程序中。很简单,我想。然而,BeginRequest我的事件 Htt
这是一段代码,我收到以下错误 #1064 - You have an error in your SQL syntax; check the manual that corresponds to yo
有没有办法用任意增量触发滚轮事件。就像 jQuery 对“点击”所做的那样: $('#selector').trigger('click'); 我需要类似的东西,只需一个滚轮即可: $('#selec
我正在尝试在配音数据库中触发时间。我想检查一下在不出现角色的电影配音中不能对角色进行配音。这是PDM: 和CDM 我是SQL的初学者,但我知道表“DUBBES”中应该有一些触发器。我试图做这样的事情,
这个问题已经有答案了: jquery programmatically click on new dom element (3 个回答) 已关闭 6 年前。 我有一个 jQuery 事件定义如下: $
主菜单的点击代码适用于类更改,但不适用于子菜单...当单击食物或鞋子等子菜单项时,它不会触发警报命令...事实上,悬停非常适合子菜单但不是活跃的 HTML
问题非常简单: $('#btn1').click(function(event){ alert( "pageX: " + event.pageX + "\npa
我使用 Spring 的调度程序 (@EnableScheduling) 并具有以下 @Scheduled 方法,该方法每分钟调用一次: @Component public class Schedul
错误 SQL 查询:文档 CREATE TRIGGER `triggers_div` AFTER INSERT ON `produits` FOR EACH ROW BEGIN INSERT INTO
我想在插入另一个表时填充表中的一些列值,并为特定列设置条件。我使用触发器: CREATE TRIGGER inserttrigger AFTER INSERT ON table1 FOR EACH R
我可以在 5.6 MySQL 环境中使用一些关于触发器的指导。我想创建一个触发器,如果发现具有相同速度的电脑的价格较低,则该触发器会停止更新。 架构是产品(制造商、型号、类型)PC(型号、速度、内
背景:我们有一个 completed_flag,默认为 0,当有人完成调查时更新为 1。我想记录这次更新发生的时间戳 在编写了这个触发器/函数以在标志从 0 触发到 1 时更新时间戳后,我怀疑我这样做
数据库中有两个表 KistStatus和 LastKistStatus .后者将保存 KistStatus 的所有“最新”值。 . KistStatus有大约 174.000 条记录,LastKist
我正在开发一个使用 APNS 的 iPhone 应用程序。我很清楚实现 APNS、创 build 备 token 的过程,等等等等……我不知道如何通过 Web 服务从提供商端触发和启动 APNS。任何
我有这个 javascript,当数量更改时会触发 update_cart... jQuery('div.woocommerce').on('change', '.qty', function
当我单击任何按钮时,click 事件不会被触发。艰难的是,我使用 $("div").on("click", "button", function () { 让它工作,但我想看到它使用 .class 工
如何在我的代码中触发 Android onCreateOptionsMenu 函数,即无需用户单击手机上的选项菜单按钮? 最佳答案 Activity.openOptionsMenu(); 就可以了 关
我将表单包装在 中然后我设置 list android:windowSoftInputMode="adjustResize" (默认 react native )。现在,当我用手指触摸事件手动聚焦一
我有一个 Android 编程问题。使用下面的代码我想验证一个字符串匹配。它验证正常,但 LogCat 显示 TextWatcher 方法在每次击键时触发两次,我不明白为什么。我希望每次击键只触发一次
我是一名优秀的程序员,十分优秀!