2009-07-06 54 views
6

我有一个WPF窗口,我想确定何时用户在桌面上移动一个窗口。我连接到LocationChanged事件,这很好,但我无法弄清楚如何确定用户何时停止移动窗口(通过释放鼠标左键)。WPF窗口LocationChanged结束

没有事件可以帮助我确定类似于LocationChangedEnded事件的事件。我尝试连接到MouseLeftButtonUp,但该事件永远不会被解雇。

任何人有任何想法?

回答

6

两种可能的方法是:

  1. 你真的不知道什么时候鼠标按钮上升。而是等待窗口停止发送这些移动事件。设置一个短暂的计时器,每当您收到一个窗口移动事件时就开始计时。如果它已经打开,重置定时器。当您收到定时器事件时,例如几百毫秒后,你可以假设用户停止移动窗口。即使使用高分辨率鼠标,当按住鼠标左键并试图保持静止时,抖动仍将继续发送移动事件。这种方法记录在here

  2. 尝试从窗口的非客户端区域捕获鼠标通知。您可以设置一个window message hook来捕获窗口消息。一旦看到第一个窗口移动事件,钩子就可以开始查找WM_NCLBUTTONUP事件。这种方法避免了计时器和猜测。但是,它对Windows允许用户定位窗口的方式进行了假设,并且在某些情况下可能会失败,例如,如果用户只用键盘移动用户(Alt + Space,M,箭头键)。

0

你想要得到的WM_WINDOWPOSCHANGED消息,它添加到您的窗口类:

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; 
} 
1

您可以监听WM_ENTERSIZEMOVE事件,它应该只火当移动开始。当用户拖动时,您可能会收到WM_MOVING和WM_MOVE事件。后者取决于他们的系统设置(例如窗口随着拖动而移动,而不是拖动轮廓)。最后,WM_EXITSIZEMOVE会指出它们何时完成。