2012-07-28 8 views
9

Tengo un problema con mi ventana personalizada (AllowTransparency, WindowStyle = None) en WPF. El método DragMove() funciona bien, pero cuando maximizo la ventana, o maximizo automáticamente con Windows 7 Aero Snap, este método no funciona en absoluto. Así que no puedo abrir la ventana con la función de arrastrar del mouse y devolverlo a WindowState.Normal. Izquierda y derecha Aero Snap funciona bien, puedo abrir y cerrar ventanas sin problemas. Pero cuando se maximiza, nada funciona, excepto la combinación Win + Down. Tal vez alguien sepa cómo resolver este problema o ¿dónde puedo encontrar otras formas de hacer una adecuada DragMove de ventanas personalizadas con funciones de funcionamiento de Aero Snap?DragMove() y Maximice

Respuesta

12

Aquí está mi método. Trate de hacerla más corta)))

private void InitHeader() 
{ 
    var border = Find<Border>("borderHeader"); 
    var restoreIfMove = false; 

    border.MouseLeftButtonDown += (s, e) => 
    { 
     if (e.ClickCount == 2) 
     { 
      if ((ResizeMode == ResizeMode.CanResize) || 
       (ResizeMode == ResizeMode.CanResizeWithGrip)) 
      { 
       SwitchState(); 
      } 
     } 
     else 
     { 
      if (WindowState == WindowState.Maximized) 
      { 
       restoreIfMove = true; 
      } 

      DragMove(); 
     } 
    }; 
    border.MouseLeftButtonUp += (s, e) => 
    { 
     restoreIfMove = false; 
    }; 
    border.MouseMove += (s, e) => 
    { 
     if (restoreIfMove) 
     { 
      restoreIfMove = false; 
      var mouseX = e.GetPosition(this).X; 
      var width = RestoreBounds.Width; 
      var x = mouseX - width/2; 

      if (x < 0) 
      { 
       x = 0; 
      } 
      else 
      if (x + width > screenSize.X) 
      { 
       x = screenSize.X - width; 
      } 

      WindowState = WindowState.Normal; 
      Left = x; 
      Top = 0; 
      DragMove(); 
     } 
    }; 
} 

private void SwitchState() 
{ 
    switch (WindowState) 
    { 
     case WindowState.Normal: 
     { 
      WindowState = WindowState.Maximized; 
      break; 
     } 
     case WindowState.Maximized: 
     { 
      WindowState = WindowState.Normal; 
      break; 
     } 
    } 
} 

(Para obtener ScreenSize utilizo métodos nativos)

+0

¡Impresionante! ¡Muchas gracias! –

+0

@groaner ¿Puedes indicar el método nativo screenSize que usaste? – egfconnor

9

solución de groaner no funciona correctamente con múltiples configuraciones del monitor, sobre todo cuando el monitor principal no es la más a la izquierda.

Aquí está mi solución basada en la que maneja las configuraciones de monitor único o múltiple correctamente. En este código, 'rctHeader' es un rectángulo definido en el XAML.

private bool mRestoreIfMove = false; 


    public MainWindow() 
    { 
     InitializeComponent(); 
    } 


    private void SwitchWindowState() 
    { 
     switch (WindowState) 
     { 
      case WindowState.Normal: 
       { 
        WindowState = WindowState.Maximized; 
        break; 
       } 
      case WindowState.Maximized: 
       { 
        WindowState = WindowState.Normal; 
        break; 
       } 
     } 
    } 


    private void rctHeader_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     if (e.ClickCount == 2) 
     { 
      if ((ResizeMode == ResizeMode.CanResize) || (ResizeMode == ResizeMode.CanResizeWithGrip)) 
      { 
       SwitchWindowState(); 
      } 

      return; 
     } 

     else if (WindowState == WindowState.Maximized) 
     { 
      mRestoreIfMove = true; 
      return; 
     } 

     DragMove(); 
    } 


    private void rctHeader_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
    { 
     mRestoreIfMove = false; 
    } 


    private void rctHeader_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (mRestoreIfMove) 
     { 
      mRestoreIfMove = false; 

      double percentHorizontal = e.GetPosition(this).X/ActualWidth; 
      double targetHorizontal = RestoreBounds.Width * percentHorizontal; 

      double percentVertical = e.GetPosition(this).Y/ActualHeight; 
      double targetVertical = RestoreBounds.Height * percentVertical; 

      WindowState = WindowState.Normal; 

      POINT lMousePosition; 
      GetCursorPos(out lMousePosition); 

      Left = lMousePosition.X - targetHorizontal; 
      Top = lMousePosition.Y - targetVertical; 

      DragMove(); 
     } 
    } 



    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetCursorPos(out POINT lpPoint); 


    [StructLayout(LayoutKind.Sequential)] 
    public struct POINT 
    { 
     public int X; 
     public int Y; 

     public POINT(int x, int y) 
     { 
      this.X = x; 
      this.Y = y; 
     } 
    } 


} 
4

En WPF, lo recomiendo el uso de Control.PointToScreen cuando se restaura la ventana antes de su Window.DragMove. PointToScreen también manejará múltiples configuraciones de monitores. Esto simplificaría la restauración a lo siguiente:

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 
     if(e.ClickCount == 2) 
     { 
      if(ResizeMode != ResizeMode.CanResize && 
       ResizeMode != ResizeMode.CanResizeWithGrip) 
      { 
       return; 
      } 

      WindowState = WindowState == WindowState.Maximized 
       ? WindowState.Normal 
       : WindowState.Maximized; 
     } 
     else 
     { 
      mRestoreForDragMove = WindowState == WindowState.Maximized; 
      DragMove(); 
     } 
    } 

    private void OnMouseMove(object sender, MouseEventArgs e) 
    { 
     if(mRestoreForDragMove) 
     { 
      mRestoreForDragMove = false; 

      var point = PointToScreen(e.MouseDevice.GetPosition(this)); 

      Left = point.X - (RestoreBounds.Width * 0.5); 
      Top = point.Y; 

      WindowState = WindowState.Normal; 

      DragMove(); 
     } 
    } 

    private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
    { 
     mRestoreForDragMove = false; 
    } 

    private bool mRestoreForDragMove; 
+0

Esta solución funciona perfectamente, exactamente lo que estaba buscando. Gracias por compartir. – Al0x

+0

Comparado con las otras soluciones, esto funciona mejor: tiene fallas menores, pero funciona muy bien. –

2

Un poco tarde para otra respuesta, pero mi código era más simple así que lo pondré aquí. Como mencionan, la alineación a la izquierda y a la derecha funciona bien, pero cuando la ventana se Maximiza o se ajusta a los límites superiores de la pantalla y se maximiza, ¡el método DragMove no funcionará!


Sólo controlar el evento MOUSE_DOWN en el elemento que desea arrastrar con este aspecto:

private void TitleBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
{ 
    if (WindowState == WindowState.Maximized) 
    { 
     var point = PointToScreen(e.MouseDevice.GetPosition(this)); 

     if (point.X <= RestoreBounds.Width/2) 
      Left = 0; 

     else if (point.X >= RestoreBounds.Width) 
      Left = point.X - (RestoreBounds.Width - (this.ActualWidth - point.X)); 

     else 
      Left = point.X - (RestoreBounds.Width/2); 

     Top = point.Y - (((FrameworkElement)sender).ActualHeight/2); 
     WindowState = WindowState.Normal; 
    } 
    DragMove(); 
} 

espero que ayude a alguien!

+0

Ocasionalmente sucede que la ventana vuelve a un estado normal pero no ancla al mouse, lo cual es realmente irritante. –

Cuestiones relacionadas