【问题标题】:C# Windows (touch -> click/focus) messages between Form and Controls (WM_xxx)窗体和控件 (WM_xxx) 之间的 C# Windows(触摸 -> 单击/聚焦)消息
【发布时间】:2015-10-13 14:07:40
【问题描述】:

我有一个第 3 方开源控件(实际上哪个并不重要,但它的 CefSharp 的 Chromium Web 浏览器 [v 43])。

最初,如果在控件内部单击时打开了表单菜单,则存在一个问题,该菜单不会自行关闭(好像控件正在吞噬单击事件)。

为了避免这种情况,示例应用程序建议截取表单和控件之间的WM_MOUSEACTIVATE 消息,并通过将WM_NCLBUTTONDOWN 发布回包含表单上的元素(在我的例子中是面板栏)来做出反应。这解决了这个问题。

然而,它创造了另一个。现在,一旦您在控件内部(触摸屏)至少触摸 3 次,您就不能再触摸该控件之外的元素。您必须用鼠标单击 [外部元素] 才能恢复再次响应触摸事件所需的焦点水平。

我发现如果我还截获WM_SETCURSOR 消息(到控件)并阻塞泵5ms(Thread.Sleep()),那么问题就会神奇地消失。

我很想知道发生了什么。我介于这是线程/上下文问题的理论之间,或者延迟 WM_SETCURSOR 消息是允许表单中的相邻消息首先处理(这不可能是真的,因为它们共享同一个线程)。

所以,我运行了一个测试(没有 5ms 的睡眠)并实时记录了控件和表单接收到的所有消息。在测试过程中,我用鼠标点击了我的面板栏(浏览器控件上方),然后触摸(长和短)控件内部的各个区域,然后再次触摸该栏(被忽略)。

以下是消息:

10/13/2015 02:37:00.295 PM  Form: WM_PARENTNOTIFY       1. [Click bar]
10/13/2015 02:37:00.295 PM  Form: WM_MOUSEACTIVATE

10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST      2. [Touch 1 -long]
10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.458 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:05.458 PM  Form: 587
10/13/2015 02:37:05.458 PM  Chromium: 587
10/13/2015 02:37:05.458 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:05.458 PM  Chromium: 585
10/13/2015 02:37:05.458 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.458 PM  Chromium: 716
10/13/2015 02:37:05.458 PM  Chromium: WM_TOUCH  (x23)
10/13/2015 02:37:05.458 PM  Chromium: 582
10/13/2015 02:37:05.458 PM  Chromium: 581       (x22)
10/13/2015 02:37:05.674 PM  Chromium: 583
10/13/2015 02:37:05.674 PM  Chromium: 586
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_MOUSEMOVE
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:05.674 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_LBUTTONDOWN
10/13/2015 02:37:05.674 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:05.674 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:05.674 PM  Chromium: WM_LBUTTONUP

10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST      3. [Touch 2 -long]
10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.509 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:10.509 PM  Form: 587
10/13/2015 02:37:10.509 PM  Chromium: 587
10/13/2015 02:37:10.509 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:10.509 PM  Chromium: 585
10/13/2015 02:37:10.509 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.509 PM  Chromium: 716
10/13/2015 02:37:10.509 PM  Chromium: WM_TOUCH  (x27)
10/13/2015 02:37:10.509 PM  Chromium: 582
10/13/2015 02:37:10.509 PM  Chromium: 581       (x25)
10/13/2015 02:37:10.755 PM  Chromium: 583
10/13/2015 02:37:10.755 PM  Chromium: 586
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_MOUSEMOVE
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:10.755 PM  Chromium: WM_MOUSEACTIVATE
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_LBUTTONDOWN
10/13/2015 02:37:10.755 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:10.755 PM  Chromium: WM_SETCURSOR
10/13/2015 02:37:10.755 PM  Chromium: WM_LBUTTONUP

10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST      4. [Touch 3 -short]
10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:25.525 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:25.525 PM  Form: 587
10/13/2015 02:37:25.525 PM  Chromium: 587
10/13/2015 02:37:25.525 PM  Chromium: 585
10/13/2015 02:37:25.525 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:25.525 PM  Chromium: 716
10/13/2015 02:37:25.525 PM  Chromium: WM_TOUCH  (x7)
10/13/2015 02:37:25.525 PM  Chromium: 582
10/13/2015 02:37:25.525 PM  Chromium: 581       (x5)
10/13/2015 02:37:25.586 PM  Chromium: 583
10/13/2015 02:37:25.586 PM  Chromium: 586

10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST      5. [Touch 4 -short]
10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:30.440 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:30.440 PM  Form: 587
10/13/2015 02:37:30.440 PM  Chromium: 587
10/13/2015 02:37:30.440 PM  Chromium: 585
10/13/2015 02:37:30.440 PM  Chromium: WM_NCHITTEST
10/13/2015 02:37:30.440 PM  Chromium: 716
10/13/2015 02:37:30.440 PM  Chromium: WM_TOUCH  (x10)
10/13/2015 02:37:30.440 PM  Chromium: 582
10/13/2015 02:37:30.440 PM  Chromium: 581       (x8)
10/13/2015 02:37:30.518 PM  Chromium: 583
10/13/2015 02:37:30.518 PM  Chromium: 586

10/13/2015 02:37:35.324 PM  Form: WM_NCHITTEST          6. [Bar (i button) touch -ignored]
10/13/2015 02:37:35.324 PM  Form: WM_NCHITTEST
10/13/2015 02:37:35.324 PM  Form: WM_PARENTNOTIFY
10/13/2015 02:37:35.324 PM  Form: 587
10/13/2015 02:37:35.324 PM  Form: 282

据此,第 3 次和第 4 次触球打破了焦点。我们可以看到 chromium 控件在 586 之后停止接收最后一串消息。我猜它缺少 WM_PARENTNOTIFY 备份到导致问题的表单。

我找不到有关 282、581、582、583、586 和 587 消息的任何信息。我也许可以对 586 消息做出反应,然后手动将WM_PARENTNOTIFY 发布到表单中?不知道快速连续接收两个会有什么效果?

有人知道为什么WM_SETCURSOR 上的 5 毫秒睡眠会保持这些消息畅通吗?

或者有什么更好的解决方法?

【问题讨论】:

    标签: c# windows-messages cefsharp message-pump


    【解决方案1】:

    一旦我包含了面板控件、按钮和所有我能想到的鼠标事件,我就能发现一个模式:

    这是一个有效的触摸:

    ....
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:10.263 PM  Chromium: WM_MOUSEMOVE
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Form: WM_PARENTNOTIFY
    10/14/2015 01:00:10.263 PM  Chromium: WM_MOUSEACTIVATE              <--
    10/14/2015 01:00:10.263 PM  panelBrowserHeader: WM_NCLBUTTONDOWN    <--
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR                  <--
    10/14/2015 01:00:10.263 PM  Chromium: WM_LBUTTONDOWN
    10/14/2015 01:00:10.263 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:10.263 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:10.263 PM  Chromium: WM_LBUTTONUP
    

    这是一个没有:

    ....
    10/14/2015 01:00:15.240 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:15.240 PM  Chromium: WM_SETCURSOR
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSEMOVE
    10/14/2015 01:00:15.240 PM  Chromium: WM_NCHITTEST
    10/14/2015 01:00:15.240 PM  Form: WM_PARENTNOTIFY
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSEACTIVATE              <--
    10/14/2015 01:00:15.240 PM  Chromium: WM_SETCURSOR                  <--
    10/14/2015 01:00:15.240 PM  panelBrowserHeader: WM_NCLBUTTONDOWN    <--
    10/14/2015 01:00:15.240 PM  Chromium: WM_LBUTTONDOWN
    10/14/2015 01:00:15.240 PM  Chromium: WM_MOUSELEAVE     
    

    问题是,WM_NCLBUTTONDOWN 事件(作为对 WM_MOUSEACTIVATE 消息的反应而发布)有时会在下一个计划的 WM_SETCURSOR 消息之后发生。这似乎给人一种触摸事件在其原始控件范围之外完成的错觉,因此它触发了自己的 WM_MOUSELEAVE 消息。

    通过延迟 WM_SETCURSOR 消息,它可以确保它们以正确的顺序触发。

    我仍然对此感到困惑,因为我确信消息泵是一个单线程循环时间,它通过每个控件的消息队列切分它的方式。因此,当我的 Chromium 控件收到 WM_CURSOR 消息时阻止执行,我以为我阻止了该 GUI 线程上存在的所有消息队列。

    不管怎样,它回答了为什么这样一个随机的“修复”会绕过这个问题。

    【讨论】:

    • 由于没有人为这个问题做出贡献,我不接受这个作为关闭它的答案,但我怀疑它的准确性。消息肯定是按顺序处理的,所以会发生其他事情来给人一种他们没有的错觉
    猜你喜欢
    • 2011-02-21
    • 1970-01-01
    • 2016-11-17
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 2012-08-27
    • 1970-01-01
    • 2013-08-10
    相关资源
    最近更新 更多