DragMove() and Maximize

Here is my method. Try make it shorter )))

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

(To get screenSize I use native methods)


A little late for another answer, but my code was simpler so I'll put it here. The left and right snapping works just fine but when the window is Maximized or snaps to upper screen bounds and maximizes, the DragMove method will not work! So here is what I did:


Just handle the Mouse_Down Event on the element you want to drag with like this:

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(); 
}

I hope it helps someone!


Groaner's solution does not function properly with multiple monitor setups, especially where the primary monitor is not the left-most.

Here is my solution based on his which handles single or multiple monitor setups properly. In this code 'rctHeader' is a Rectangle defined in the 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;
        }
    }


}

In WPF I would highly recommend using Control.PointToScreen when restoring the window before your Window.DragMove. PointToScreen will also handle multiple monitor setups. This would simplify the restore to the following:

    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;