确定何时移动 WPF 窗口
Posted
技术标签:
【中文标题】确定何时移动 WPF 窗口【英文标题】:Determining when a WPF window is being moved 【发布时间】:2013-09-04 08:08:12 【问题描述】:我正在开发一个派生自 WPF Window
类的类,该类的行为类似于名为 AppBarWindow
的应用程序工具栏窗口。我已经能够找到各种 WinForms 实现,但没有 WPF 实现。
我已经编写了很多代码,但我需要知道用户何时开始在屏幕上拖动窗口以及何时停止,因为窗口的行为会有所不同。默认的 WPF 处理不太正确,所以我实现了自己的窗口过程并使用HwndSource
对象安装它。
我在一个没有非客户区的应用程序中工作。在这种情况下,有一个 LeftMouseButtonDown
事件处理程序将标志设置为 true,然后调用 DragMove
方法来拖动窗口。当该方法返回时,我将标志设置为 false。一切正常。
但我现在正在研究一个不会使用DragMove
方法的通用类。我可以为窗口添加另一个 LeftMouseButtonDown
处理程序,但我不相信如果鼠标在非客户区,它会被调用。
在这种情况下,我将如何检测用户正在拖动窗口以及何时停止?
【问题讨论】:
【参考方案1】:通过在拖动窗口时监视从 Win32 发送到我的窗口的消息,我找到了我需要知道的内容。
简而言之,当窗口开始移动时,Windows 会发送以下消息:
WM_ENTERSIZEMOVE
接下来,Windows 依次向我的窗口过程发送以下消息:
WM_MOVING WM_WINDOWPOSCHANGING WM_GETMINMAXINFO WM_WINDOWPOSCHANGED WM_MOVE这些后面是代码为 0xc310 的消息。这在任何地方都没有记录,所以我猜这是 .NET / WPF 在内部使用的。
这 6 条消息在鼠标移动时重复发送,窗口跟随在它后面。
最后,当你松开鼠标左键时,Windows 会发送:
WM_EXITSIZEMOVE所以我需要监听 WM_ENTERSIZEMOVE 和 WM_EXITSIZEMOVE 消息。
【讨论】:
【参考方案2】:在这种情况下,Window.LocationChanged
事件不会为您提供帮助。
http://msdn.microsoft.com/en-us/library/system.windows.window.locationchanged.aspx
【讨论】:
不,不会。正如我在问题中所说,“默认的 WPF 处理不太正确,所以我实现了自己的窗口过程。”我需要在那个级别进行处理。Window.LocationChanged
在这个过程中为时已晚。我需要在 WPF 收到消息之前对其进行处理。
当包含的 WPF 窗口被移动时,我需要这个事件来关闭一个弹出控件。该活动对我有用,因为我可以看到弹出窗口及时关闭。【参考方案3】:
正如 Tony 指出的那样,窗口拖动涉及一些窗口消息。这是一个可能有帮助的枚举:
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
【讨论】:
以上是关于确定何时移动 WPF 窗口的主要内容,如果未能解决你的问题,请参考以下文章