在 Winforms 中,PreviewKeyDown() 从未针对任何键触发

2024-05-05

我最初试图让我的程序获取箭头键(上、下、左、右)的输入,但发现在 KeyDown() 中这些键从未出现过。后来我发现我可以通过进入 PreviewKeyDown() 函数并设置来启用箭头键:

e.IsInputKey = true;

及其周围的任何条件和逻辑。问题是当我编写函数时:

private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{ /*whatever logic goes here*/}

它从未发射过;我什至设置了一个断点,以确保在函数内部触发。另外,我尝试过:

this.Focus()

在构造函数中以确保主窗体具有焦点,但这没有什么区别。唯一有效的是将焦点设置到我创建的按钮上,并且该按钮还通过调用上面的 Form1_PreviewKeyDown() 来触发 PreviewKeyDown 事件。

所以现在我有了一个工作方法,但是任何人都可以帮助我理解为什么它最初从未被触发过吗?我假设由于某种原因,表单的 PreviewKeyEvent 永远不会触发,但我真的不知道为什么。


Why

您可以尝试这个小实验:制作一个带有两个按钮的表单,覆盖PreviewKeyDown(),设置断点,运行,然后按左/右箭头键。这PreviewKeyDown()方法将不会运行。但删除按钮和覆盖will叫做。

造成差异的原因是 WinForms 本身处理箭头键以进行导航。当您有按钮和文本框等输入控件时,WinForms 将自动接管某些特殊键,例如TAB和箭头键从一个控件导航到下一个控件。这样做可能是因为很多人喜欢能够使用键盘进行导航,如果您弄乱导航键,很容易破坏他们的功能。最好为您处理它们,这样您在玩其他键时就不会意外弄乱它们。

一个简单的解决方法是检测您何时失去焦点并将其收回。但这不起作用,因为您的表单不会失去焦点。输入控件具有焦点,并且它们是表单的一部分,因此表单仍然(技术上,间接地)具有焦点。仅当您在其他窗口上单击外部时,它才会失去焦点。

更好的解决方法包括更好地理解 .Net 解释器下面“幕后”发生的事情。 WinForms 相当接近地模仿了这个级别,因此它是了解 WinForms 功能的有用指南。

当 Windows 将输入(如击键)发送到您的程序时,您的窗体并不总是第一个获取输入的。输入将转到具有焦点的控件。在这种情况下,该控件是其中一个按钮(我假设焦点发光首先被隐藏,以证明为什么当看起来没有选择任何内容时,第一次笔画没有发生任何事情)。

一旦按钮获得输入,它就可以决定接下来发生什么。它可以将输入传递给下一个排队的人,做一些事情并then传递它,或者完全处理输入并且根本不传递它。

对于普通的字母键,按钮决定不知道如何处理它们,而是将它们传递给其基类。基类也不知道,因此它将密钥转发。最终,它击中了Control类,它通过将其传递给任何一个来处理它Control是在其Parent财产。如果这种情况持续足够长的时间,您的表单最终将有机会处理输入。

简而言之,WinForms 首先将输入提供给最具体的目标,然后处理越来越普遍的事情,直到有人知道如何处理输入。

然而,在使用箭头键的情况下,按钮知道如何处理这些。它通过将焦点传递到下一个输入控件来处理它们。此时,按钮声明输入已完全处理,吞下密钥并且不给其他任何人查看它的机会。按下按钮后没有人知道击键发生过。

这就是为什么你的PreviewKeyDown()没有调用 override。仅当您的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。孩子的PreviewKeyDown()方法将首先出现,然后箭头将被视为不是命令键,并且您的ProcessCmdKey()不会被调用。

ProcessCmdKey()是为了上下文菜单处理 http://msdn.microsoft.com/en-us/library/vstudio/system.windows.forms.control.processcmdkey%28v=vs.100%29.aspx。我不确定将它用于上下文菜单以外的其他用途是否明智,但是甚至微软也推荐它用于类似的用途 http://support.microsoft.com/kb/320584而且它似乎确实有效,因此可能值得考虑。

结论

长话短说,导航键是用来导航的。弄乱它们可能会给键盘用户带来不愉快的用户体验,因此 .Net 使弄乱它们变得困难,因此我们会鼓励您去弄乱其他键。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Winforms 中,PreviewKeyDown() 从未针对任何键触发 的相关文章

  • 无法使用已与其底层 RCW 分离的 COM 对象。在 oledb 中

    我收到此错误 但我不知道我做错了什么 下面的代码在backrgroundworker中 将异常详细信息复制到剪贴板 System Runtime InteropServices InvalidComObjectException 未处理 通
  • 当我使用“control-c”关闭发送对等方的套接字时,为什么接收对等方的套接字不断接收“”

    我是套接字编程的新手 我知道使用 control c 关闭套接字是一个坏习惯 但是为什么在我使用 control c 关闭发送进程后 接收方上的套接字不断接收 在 control c 退出进程后 发送方的套接字不应该关闭吗 谢谢 我知道使用
  • 获取按下的按钮的返回值

    我有一个在特定事件中弹出的表单 它从数组中提取按钮并将标签值设置为特定值 因此 如果您要按下或单击此按钮 该函数应返回标签值 我怎样才能做到这一点 我如何知道点击了哪个按钮 此时代码返回 DialogResult 但我想从函数返回 Tag
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 使闭包捕获的变量变得易失性

    闭包捕获的变量如何与不同线程交互 在下面的示例代码中 我想将totalEvents 声明为易失性的 但C 不允许这样做 是的 我知道这是错误的代码 这只是一个例子 private void WaitFor10Events volatile
  • 当 contains() 工作正常时,xpath 函数ends-with() 工作时出现问题

    我正在尝试获取具有以特定 id 结尾的属性的标签 like span 我想获取 id 以 国家 地区 结尾的跨度我尝试以下xpath span ends with id Country 但我得到以下异常 需要命名空间管理器或 XsltCon
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • 如果使用 SingleOrDefault() 并在数字列表中搜索不在列表中的数字,如何返回 null?

    使用查询正数列表时SingleOrDefault 当在列表中找不到数字时 如何返回 null 或像 1 这样的自定义值 而不是类型的默认值 在本例中为 0 你可以使用 var first theIntegers Cast
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 从路径中获取文件夹名称

    我有一些路c server folderName1 another name something another folder 我如何从那里提取最后一个文件夹名称 我尝试了几件事 但没有成功 我只是不想寻找最后的 然后就去休息了 Thank
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 如何使我的表单标题栏遵循 Windows 深色主题?

    我已经下载了Windows 10更新包括黑暗主题 文件资源管理器等都是深色主题 但是当我创建自己的 C 表单应用程序时 标题栏是亮白色的 如何使我自己的桌面应用程序遵循我在 Windows 中设置的深色主题 你需要调用DwmSetWindo
  • 需要哪个版本的 Visual C++ 运行时库?

    microsoft 的最新 vcredist 2010 版 是否包含以前的版本 2008 SP1 和 2005 SP1 还是我需要安装全部 3 个版本 谢谢 你需要所有这些
  • C - 直接从键盘缓冲区读取

    这是C语言中的一个问题 如何直接读取键盘缓冲区中的数据 我想直接访问数据并将其存储在变量中 变量应该是什么数据类型 我需要它用于我们研究所目前正在开发的操作系统 它被称为 ICS OS 我不太清楚具体细节 它在 x86 32 位机器上运行
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框
  • 恢复上传文件控制

    我确实阅读了以下帖子 C 暂停 恢复上传 https stackoverflow com questions 1048330 pause resume upload in c 使用 HTTP 恢复上传 https stackoverflow

随机推荐

  • 在 C 中初始化结构体的静态数组

    我正在用 C 实现一个纸牌游戏 纸牌有很多种类型 每种纸牌都有大量信息 包括一些需要单独编写与其关联的脚本的操作 给定这样的结构 并且我不确定我的语法是否适合函数指针 struct CARD int value int cost This
  • GAE、JPA、XG 事务、实体组过多异常

    我知道 GAE 上的 XG 交易有 5 个实体组的限制 但我认为我在一项交易中仅使用 3 个组 商品 类别 商品类别 但仍然遇到此异常 引起原因 java lang IllegalArgumentException 在单个事务中对太多实体组
  • NuGet 未显示任何包

    I ve tried going to the URL listed for the official package source with my browser and I only get an empty list I also t
  • 带有隐藏输入的 Selenium 文件选择器[type=file]

    我有一个图像文件上传并想测试它硒 java 用户有两个选择 他可以通过从本地计算机拖放来推送图像 也可以单击 浏览 按钮 然后出现浏览器指定的文件选择器 In Selenium我尝试了不同的事情 据我所知Selenium不提供浏览器之外的操
  • 覆盖 vuetify 中的 scss 变量

    为了增加 vuetify 的 v switch 的宽度 我想修改 vuetify 的 scss 变量的值 vuetify是通过vue cli配置的 开发的代码如下 src assets css overrides scss font siz
  • Google 文档从脚本调用 ImportXML

    我在 google 文档表中使用 ImportXML 从 sistrix api 获取数据 它工作正常 但我遇到了一张纸中 50 个 ImportXML 命令的限制 因此 我使用了一个脚本 将 ImportXML 命令写入单元格 临时 公式
  • 在javascript中调用c#函数[重复]

    这个问题在这里已经有答案了 可能的重复 从 Javascript 调用 ASP NET 函数 https stackoverflow com questions 3713 call asp net function from javascr
  • Zend_Controller_Router_Route:找不到翻译器

    我正在开发一个多语言应用程序 在引导程序中有路由设置 protected function initRoutes this gt bootstrap frontController router this gt frontControlle
  • 使用 PrimarySearcher.FindAll() 时出现内存泄漏

    我也有一个使用插件和应用程序域长时间运行的服务 并且由于使用目录服务而出现内存泄漏 请注意 我正在使用 system directoryservices accountmanagement 但据我了解 它使用相同的底层 ADSI API 因
  • Spring WebFlux - 通过 webClient 转发 FilePart

    我浏览过类似的门票 即如何在 Spring WebFlux 中从 Multipart form data 流式传输文件 https stackoverflow com questions 70408075 how to stream fil
  • 在 Python 中删除表达式树及其每个子表达式树中第一个元素周围的括号

    目标是实现简化操作 删除表达式树及其每个子表达式树中第一个元素周围的括号 其中表达式作为括在各个括号中的字符串输入给出 这必须适用于任意数量的括号 例如 12 3 45 6 gt 123 45 6 删除 12 周围的括号 然后删除 45 周
  • 在 QtCreator 中查看数组内容

    调试时是否可以在 Qt Creator 中查看数组的内容 似乎检测到我的数组是一个数组而不是一个指针 此外 我可以点击一个箭头 就像展开一样 但之后什么也没有显示 当我试穿的时候std vector Qt Creator 设法按预期显示内容
  • Lucene 评分:在什么情况下使用 queryNorm?

    我对 lucene 的评分策略有点困惑 我知道Lucene的评分公式是这样的 score q d coord q d x queryNorm q X SUM
  • ASP.NET Core Web API 模板中没有个人用户帐户身份验证选项

    我有点困惑为什么最新的 ASP NET Core Web API 模板中没有个人用户帐户身份验证选项 是否仍然可以按照 MVC 模板的方式实现个人用户帐户 或者是否有意义 假设我正在创建一个独立的 Web API 它将包含我的所有业务逻辑和
  • Django FileResponse PDF - 前端的 pdf 字体更改 - (Django DRF 和 React.js)

    我在我的应用程序中使用 Django Rest Framework 和 React js 作为应用程序的一部分 我在后端生成 pdf 然后将它们发送到前端进行显示 这个功能是有效的 如果不是因为我的前端 pdf 中的字体看起来不同的话 在我
  • Django url模式多个参数(不带pk)

    我是 Django 框架的新手 有一件事困扰着我 我想要一个简单的休息电话 www abc com users 1 cantonments 1 如果我在 url 模式中使用 pk 则一切都可以开箱即用 pk pk1 pk2 但我有一些权限功
  • 如何使用 python / pywinusb 将 hid 数据发送到设备?

    我正在尝试使用 pywinusb 将输出报告发送到 pic18f4550 该设备可以接收数据 我已经使用 C 应用程序对其进行了测试 效果很好 另外 我可以使用 pywinusb 从设备读取数据 但我在尝试发送数据时遇到问题 这是我正在运行
  • 在 Flutter 中更改深色模式的文本颜色(带有动态主题)?

    当我选择深色模式时 文本变成白色 但我想将所有文本设置为白色70或其他内容 包括按钮和常规文本 如何定义深色模式的默认文本颜色 我的主题数据现在是这样的 class MyApp extends StatelessWidget overrid
  • aspnet_Profiles 表中的 PropertyValuesString 和 PropertyValuesBinary 字段有何用途?

    我认为 PropertyValuesString 用于通常是这些类型对象的键值对的值部分 但是 如果您已经将值放入 PropertyValuesString 中 那么 PropertyValuesBinary 字段会出现在哪里呢 这两个字段
  • 在 Winforms 中,PreviewKeyDown() 从未针对任何键触发

    我最初试图让我的程序获取箭头键 上 下 左 右 的输入 但发现在 KeyDown 中这些键从未出现过 后来我发现我可以通过进入 PreviewKeyDown 函数并设置来启用箭头键 e IsInputKey true 及其周围的任何条件和逻