所有Process *方法和所有消息filter的目的是什么?

我注意到,WinForms有许多处理命令或键( Process*() )和(预)过滤系统消息的方法,但是他们各自的目的对我来说还不清楚。

官方文件有些模糊,我还没有find明确而完整的答复。

我讲下面的方法:

  • PreFilterMessage(ref Message m)
  • ProcessCmdKey(ref Message msg, Keys keyData)
  • WndProc(ref Message m)
  • ProcessDialogKey(Keys keyData)
  • PreProcessMessage(ref Message msg)
  • ProcessKeyMessage(ref Message m)
  • ProcessKeyPreview(ref Message m)

一些用于拦截密钥(如ProcessCmdKeyProcessDialogKey ),另一些用于拦截消息(相互之间)。 但为什么有多less方法呢? 他们的目的和用例是什么?

我想每个方法的执行顺序是不同的。

这是我所知道的(或者我认识的):

  • PreFilterMessage :首先拦截消息。 您可以在这里停止所有以下方法的消息分发!
  • ProcessCmdKey :拦截所有按键,甚至是组合键,特殊键和命令键。 很好地检测整个表单上的快捷键(如Ctrl + D)。 您可以在这里停止密钥的分配。
  • WndProc :第二个筛选后拦截消息? 我只用它来检测用户是否点击右上angular的“X”,但我想这是可能的另一种方法!
  • ProcessDialogKey :只拦截ONE键,可能在ProcessCmdKey之后,所有键的控件事件之前。
  • PreProcessMessage :在WndProc之前和PreFilterMessage之后? 我不知道为什么它被使用。
  • ProcessKeyMessage :截获关键信息。 它似乎很less使用。
  • ProcessKeyPreview :截取预览事件之前的键? 也很less使用。

深入的,我认为这是正确的执行顺序:

  1. 预过滤
  2. 过滤
  3. 预处理
  4. 处理
  5. 活动

为什么这么多步骤?

任何信息或具体的用例将不胜感激!

本地Windows GUI应用程序通常有一个消息循环,底层winapi调用是GetMessage()。 但有很多窗口获取消息,底层的winapi调用是DispatchMessage()。 在你的.NET应用程序中,你只有一个对Application.Run()的调用,但是每个控件都有一个WndProc()方法。 它们大多数都隐藏在.NET Framework代码中,只有在覆盖它时才会公开。

一般来说,需要挂钩到消息循环中,在将消息发送到控件并到达WndProc()之前截取消息。 最显而易见的原因是键盘快捷键,无论哪个控件都有焦点,您都要对其执行操作。 如果您必须在每个控件上使用KeyDown来检测快捷方式,那当然是非常痛苦的。 不太明显的原因,例如,ActiveX控件与主机进行协商是值得注意的。

Winforms提供了很多扩展点来拦截消息。 太多了,实际上,却是一个不可避免的副作用,不想预测在什么情况下可能有用。 为了:

  • IMessageFilter.PreFilterMessage()让您在GetMessage()检索到消息后立即查看消息。 请记住,只能看到发送到消息队列的消息,底层调用是PostMessage(),您看不到已发送的消息。 这限制了用户输入,键盘和鼠标消息的可用性。 很少去修补这个,但你可以用它来使鼠标的行为不同,并检测到用户正在与你的程序进行交互。 希望自动注销用户经过一段时间不活动的程序员使用它。
  • OnPreviewKeyDown()和PreviewKeyDown事件。 具体到有重点的控制。 在测试快捷方式之前,控件拦截按键的一种方法。 例如,您可以在使用光标键移动焦点之前检测光标键。 重写IsInputKey()的替代方法。
  • PreProcessMessage()。 非常类似于PreFilterMessage,但特定于具有焦点的控件。 对于ActiveX控件很重要,我个人从来没有使用它。
  • ProcessCmdKey()。 这是实现您自己的快捷键操作的主力方法。
  • IsInputKey(),允许控件投票是否应该将通常用于导航的键发送给控件。 例如,当您使用光标键时,可以覆盖此方法。
  • ProcessDialogKey()。 就像ProcessCmdKey()一样,但是对于应该像输入键一样对待的按键进行过滤。 默认实现使键盘消息冒泡到父控件,让您选择重写ProcessCmdKey()的位置。 我想不出一个很好的理由,为什么你要重写它,而且从来没有这样做,除了停止冒泡。
  • IsInputChar()与IsInputKey非常相似,但对于KeyPress事件。 从来没有使用过它自己,但一种方式来过滤输入提前。
  • ProcessDialogChar(),可以用来给键入快捷键的按键行为。 这是不寻常的。
  • WndProc(),处理消息的主要方法。 您可以覆盖它以允许控件响应现有事件未覆盖的消息。 或者自定义现有的本地控件的行为。
  • ProcessKeyEventArgs(),这是生成键盘事件(OnKeyDown,OnKeyUp,OnKeyPress)的一般方法,由Control.WndProc()调用。 我想不出一个理由来重写它,值得注意的是实现了古怪的Form.KeyPreview属性,一个VB6的compat属性,可能是它暴露的原因。

确实是一个曲折的迷宫。

试图保持它的理智,总是覆盖ProcessCmdKey()来实现快捷键。 重写IsInputKey()让您的控件看到导航键。 而且只能覆盖WndProc()来自定义现有的控件。