2009-07-06 4 views
6

J'ai une fenêtre WPF, et je veux déterminer quand un utilisateur a fini de déplacer une fenêtre sur le bureau. J'ai connecté à l'événement LocationChanged et c'est bien, mais je ne peux pas comprendre comment déterminer quand l'utilisateur arrête de déplacer la fenêtre (en relâchant le bouton gauche de la souris).WPF Window LocationChanged terminé

Il n'y a aucun événement pour m'aider à le déterminer, quelque chose comme un événement LocationChangedEnded. J'ai essayé de me connecter à MouseLeftButtonUp mais cet événement n'est jamais déclenché.

Quelqu'un a des idées?

Répondre

6

Deux approches possibles seraient:

  1. Vous ne savez pas vraiment quand le bouton de la souris est soulevée. Au lieu de cela, vous attendez que la fenêtre arrête d'envoyer ces événements de déplacement. Mettre en place un minuteur de courte durée qui commence à cocher chaque fois que vous recevez un événement de déplacement de la fenêtre. Réinitialisez la minuterie si elle est déjà activée. Lorsque vous recevez l'événement de minuteur, par ex. après quelques centaines de millisecs, on peut supposer que l'utilisateur a arrêté de déplacer la fenêtre. Même avec une souris haute résolution, lorsque vous maintenez le bouton gauche de la souris enfoncé et que vous essayez de rester immobile, la gigue continue d'envoyer des événements de déplacement. Cette approche est documentée here.

  2. Tentative de capture des notifications de la souris à partir de la zone non-client de la fenêtre. Vous pouvez configurer un window message hook pour capturer des messages de fenêtre. Une fois que l'événement de déplacement de la première fenêtre est visible, le hook peut commencer à rechercher les événements WM_NCLBUTTONUP. Cette approche évite la minuterie et la devinette. Cependant, il fait des suppositions sur les façons dont Windows permet à l'utilisateur de positionner les fenêtres, et peut échouer dans certains cas, par ex. si l'utilisateur déplace l'utilisateur avec le clavier uniquement (Alt + Espace, M, touches fléchées).

0

Vous voulez faire passer le message WM_WINDOWPOSCHANGED, ajoutez à votre classe de fenêtre:

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

Vous pouvez écouter l'événement WM_ENTERSIZEMOVE, qui devrait tirer que lorsque le mouvement est lancé. Pendant que l'utilisateur est en train de glisser, vous pouvez recevoir les événements WM_MOVING et WM_MOVE. Ce dernier dépend des paramètres de leur système (par exemple, la fenêtre se déplace en faisant glisser, par opposition à un simple contour). Finalement, WM_EXITSIZEMOVE indiquera quand ils auront fini.

Questions connexes