确定WPF窗口正在移动的时间

6
我正在开发一个继承自WPF Window类的应用工具栏窗口,名为AppBarWindow。我已经找到了一些WinForms实现,但没有WPF实现。
我已经让很多代码能正常工作,但我需要知道用户何时开始拖动窗口以及何时停止,因为窗口的行为将有所不同。默认的WPF处理方式不太对,所以我实现了自己的窗口处理过程,并使用一个HwndSource对象进行安装。
在没有非客户端区域的工作应用程序中,我已经成功使其工作。在这种情况下,有一个LeftMouseButtonDown事件处理程序,它将标志设置为true,然后调用DragMove方法来拖动窗口。当该方法返回时,我将标志设置为false。一切都很顺利。
但是现在我正在开发通用类,该类将不使用DragMove方法。我可以为窗口添加另一个LeftMouseButtonDown处理程序,但我认为如果鼠标位于非客户端区域,则不会调用该处理程序。
在这种情况下,我将如何检测用户何时拖动窗口以及何时停止?
3个回答

10

我通过监控Win32发送到我的窗口的消息找到了需要了解的内容。

简单来说,当窗口开始移动时,Windows会发送以下消息:

WM_ENTERSIZEMOVE

接下来,Windows按顺序向我的窗口程序发送以下消息:

  • WM_MOVING
  • WM_WINDOWPOSCHANGING
  • WM_GETMINMAXINFO
  • WM_WINDOWPOSCHANGED
  • WM_MOVE

这些消息随着鼠标移动和窗口跟随而不断发送。

最后,当你释放左键时,Windows会发送:

  • WM_EXITSIZEMOVE

因此,我需要监听WM_ENTERSIZEMOVE和WM_EXITSIZEMOVE消息。


2
正如Tony所指出的,窗口拖动涉及到几个Windows消息。这里有一个枚举可能会有所帮助:
internal enum WindowsMessage
{
    /// <summary>Sent after a window has been moved.</summary>
    WM_MOVE = 0x0003,
    /// <summary>
    /// Sent to a window when the size or position of the window is about to change.
    /// An application can use this message to override the window's default maximized size and position,
    /// or its default minimum or maximum tracking size.
    /// </summary>
    WM_GETMINMAXINFO = 0x0024,
    /// <summary>
    /// Sent to a window whose size, position, or place in the Z order is about to change as a result
    /// of a call to the SetWindowPos function or another window-management function.
    /// </summary>
    WM_WINDOWPOSCHANGING = 0x0046,
    /// <summary>
    /// Sent to a window whose size, position, or place in the Z order has changed as a result of a
    /// call to the SetWindowPos function or another window-management function.
    /// </summary>
    WM_WINDOWPOSCHANGED = 0x0047,
    /// <summary>
    /// Sent to a window that the user is moving. By processing this message, an application can monitor
    /// the position of the drag rectangle and, if needed, change its position.
    /// </summary>
    WM_MOVING = 0x0216,
    /// <summary>
    /// Sent once to a window after it enters the moving or sizing modal loop. The window enters the
    /// moving or sizing modal loop when the user clicks the window's title bar or sizing border, or
    /// when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the wParam
    /// parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is complete
    /// when DefWindowProc returns.
    /// <para />
    /// The system sends the WM_ENTERSIZEMOVE message regardless of whether the dragging of full windows
    /// is enabled.
    /// </summary>
    WM_ENTERSIZEMOVE = 0x0231,
    /// <summary>
    /// Sent once to a window once it has exited moving or sizing modal loop. The window enters the
    /// moving or sizing modal loop when the user clicks the window's title bar or sizing border, or
    /// when the window passes the WM_SYSCOMMAND message to the DefWindowProc function and the
    /// wParam parameter of the message specifies the SC_MOVE or SC_SIZE value. The operation is
    /// complete when DefWindowProc returns.
    /// </summary>
    WM_EXITSIZEMOVE = 0x0232
}

2

不会的。正如我在问题中所说,“默认的WPF处理方式不太正确,因此我实现了自己的窗口过程。” 我需要在那个级别上进行处理。 Window.LocationChanged 处理来得太晚了。我需要在WPF收到消息之前进行处理。 - Tony Vitabile
我需要这个事件来在包含WPF窗口移动时关闭弹出控件。对我来说,这个事件起作用,因为我可以看到弹出窗口及时关闭。 - user8276908

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接