我有一个WPF窗口,我想确定用户何时完成在桌面上移动窗口。我连接到LocationChanged事件,这很好,但我无法弄清楚如何确定用户何时停止移动窗口(通过释放鼠标左键)。
没有任何事情可以帮助我确定,比如LocationChangedEnded事件。我尝试连接到MouseLeftButtonUp,但该事件永远不会被触发。
任何人都有任何想法?
答案 0 :(得分:7)
两种可能的方法是:
您实际上并不知道鼠标按钮何时被抬起。相反,您等待窗口停止发送这些移动事件。设置一个短暂的计时器,每次收到窗口移动事件时都会开始计时。如果计时器已经打开,请重置计时器。当您收到计时器事件时,例如在几百毫秒之后,您可以假设用户停止移动窗口。即使使用高分辨率鼠标,当按住鼠标左键并试图保持静止时,抖动将继续发送移动事件。这种方法记录在案here。
尝试从窗口的非客户区域捕获鼠标通知。您可以设置window message hook来捕获窗口消息。一旦看到第一个窗口移动事件,钩子就可以开始寻找WM_NCLBUTTONUP事件。这种方法避免了计时器和猜测。但是,它假设Windows允许用户定位窗口的方式,并且在某些情况下可能会失败,例如,如果用户仅使用键盘移动用户(Alt + Space,M,箭头键)。
答案 1 :(得分:1)
您可以收听WM_ENTERSIZEMOVE事件,该事件只应在移动开始时触发。当用户拖动时,您可能会收到WM_MOVING和WM_MOVE事件。后者取决于他们的系统设置(例如,窗口在拖动时移动,而不是仅拖动轮廓)。最后,WM_EXITSIZEMOVE将指示它们何时完成。
答案 2 :(得分:0)
您想要获取WM_WINDOWPOSCHANGED消息,将其添加到您的Window类中:
internal enum WM
{
WINDOWPOSCHANGING = 0x0047,
}
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPOS
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int cx;
public int cy;
public int flags;
}
private override void OnSourceInitialized(EventArgs ea)
{
HwndSource hwndSource = (HwndSource)HwndSource.FromVisual((Window)this);
hwndSource.AddHook(DragHook);
}
private static IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
{
switch ((WM)msg)
{
case WM.WINDOWPOSCHANGED:
{
WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
if ((pos.flags & (int)SWP.NOMOVE) != 0)
{
return IntPtr.Zero;
}
Window wnd = (Window)HwndSource.FromHwnd(hwnd).RootVisual;
if (wnd == null)
{
return IntPtr.Zero;
}
// ** do whatever you need here **
// the new window position is in the pos variable
// just note that those are in Win32 "screen coordinates" not WPF device independent pixels
}
break;
}
return IntPtr.Zero;
}
答案 3 :(得分:0)
您可能对我在此处发布的答案感兴趣:
How do you disable Aero Snap in an application?
答案包含一种可靠的方法来检测窗口移动的开始/结束,以便禁用Aero snap。