【问题标题】:Why does handling WM_NCCALCSIZE cause my window to jump?为什么处理 WM_NCCALCSIZE 会导致我的窗口跳转?
【发布时间】:2010-09-16 15:03:52
【问题描述】:

我有一个 WPF 应用程序,它可以捕捉到屏幕边缘(如果您在屏幕边缘的 20 像素内,我只是设置了窗口的 .Top 或 .Left),但我最近添加了一些代码 provided by the WPF SDK Team 到“窗口镶边的混乱”,虽然它工作得很好(screenshot),但它导致“snapto”意外移动窗口(例如:当它应该直接向下捕捉到底部时它会跳到左边)

我已经把它缩小到他们对 WM_NCCALCSIZE 的处理......这真的很奇怪,因为他们基本上什么都不做,他们只是说他们处理它,然后返回 0。

根据 WM_NCCALCSIZE 的文档,这只会导致整个窗口被视为客户端(没有非客户端边缘),但不知何故,这也意味着每当我的 snap-to 代码将窗口向下移动到底部在屏幕上,它也向左移动了大约 134 像素……(移动到其他边缘也有类似的副作用),只要我按住鼠标拖动它,它就会从它应该在的位置来回闪烁。如果我将 WM_NCCALCSIZE 处理注释掉,则 snap-to 会按应有的方式工作(但表单看起来不正确)。

我已经在 WM_NCCALCSIZE 处理程序中尝试了所有我能做的事情,但我无法阻止它向左跳转......当然,WM_NCCALCSIZE 只有在窗口大小发生变化时才会被调用,所以我不明白它首先是如何导致这种情况的!

附:如果要实际看代码,已经是on CodePlex了,在两个文件里找_HandleNCCalcSizeOnWindowLocationChanged

【问题讨论】:

  • 当 WM_NCCALCSIZE 处理程序返回 0 时,wParam 和 lParam 是什么?文档说“如果 wParam 为 TRUE 并且应用程序返回零,则保留旧客户区并与新客户区的左上角对齐”,这听起来可能是您正在发生的事情。
  • 我从来没有弄清楚这一点,但我确实确定如果我们在 WM_WINDOWPOSCHANGING 消息而不是 WPF WindowPositionChanged 事件期间调整窗口位置,问题就会消失。因此,找到了解决方法。继续生活。

标签: wpf windows winapi pinvoke


【解决方案1】:

发生这种情况的原因是处理 WM_NCCALCSIZE 会改变窗口的整体大小......但是如果您正在移动窗口,则在 WM_MOVEWM_WINDOWPOSCHANGED 期间更改您的位置(对应于 WPF WindowPositionChanged 事件)导致另一个 WM_NCCALCSIZE 消息...

WM_NCCALCSIZE 期间进行更改(即使只是断言您处理了该消息)会导致对WM_MOVE 的另一个调用...这使您进入一个循环,其中 positionchanged 消息的“FROM”部分保持不变(使窗口从它开始的位置“跳”到你在WM_MOVE 期间调整到的位置,因为它在WM_NCCALCSIZE 之后变回来)。

正确的方法

你要做的就是服从Raymond Chen和handle WM_WINDOWPOSCHANGING instead。它发生在这些其他消息之前,这样它们就不会相互干扰!

【讨论】:

    【解决方案2】:

    wParam 似乎总是为 TRUE (1) 而 lParam 是一个 NCCALCSIZE_PARAMS ...

    目的是完全按照您所说的进行:强制整个窗口成为“客户端”,然后使用 Vista DWM apis 将框架扩展到客户端区域。我只是不明白为什么它向左移动这么远......

    如果我跟踪或断点 HandleNCCalcSize 方法,当我调整窗口大小时(当它位于边缘以便触发 snap-to 时),NCCalcSize 会被调用两次:一次是它应该在的位置,然后是向左,结束的地方。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-18
      • 2019-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多