Drag a WPF Form around the desktop

12,546

Solution 1

You can use the Window.DragMove method in the mouse down event of the window.

Solution 2

Previous answers hit on the answer, but the full example is this:

   private void Window_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            DragMove();
        }
    }

Solution 3

Here is some simplified code to drag the WPF form around your screen. You might have seen some of this code on different posts, I just modified it to fit the needs of dragging the WPF form.

Keep in mind we need to grab the form position on the MouseLeftButtonDown, so we can keep the mouse pointer positioned in the same spot on the form as we are dragging it around the screen.

You will also need to add the following reference to get the mouse position relative to the screen: System.Windows.Forms

Properties Needed:

private bool _IsDragInProgress { get; set; }
private System.Windows.Point _FormMousePosition {get;set;}

Code:

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            this._IsDragInProgress = true;
            this.CaptureMouse();
            this._FormMousePosition = e.GetPosition((UIElement)this);
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (!this._IsDragInProgress)
                return;

            System.Drawing.Point screenPos = (System.Drawing.Point)System.Windows.Forms.Cursor.Position;
            double top = (double)screenPos.Y - (double)this._FormMousePosition.Y;
            double left = (double)screenPos.X - (double)this._FormMousePosition.X;
            this.SetValue(MainWindow.TopProperty, top);
            this.SetValue(MainWindow.LeftProperty, left);
            base.OnMouseMove(e);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            this._IsDragInProgress = false;
            this.ReleaseMouseCapture();
            base.OnMouseLeftButtonUp(e);
        }

Solution 4

on windows load or the grid load event you can use a delegate to trigger the DragMove() function.

`private void Grid_Loaded(object sender, RoutedEventArgs e) {

        this.MouseDown += delegate{DragMove();};

    }`

Solution 5

If you, like me, want to have a little bit more control about the DoDragMove() - says, to have the window always stay in the border of the current desktop, I have made this.

Usage:

public partial class MainWindow : Window
{
    private WindowsDragger _dragger;

    public MainWindow()
    {
        InitializeComponent();
        _dragger = new WindowsDragger(this);
    }
}

Helper Class:

class WindowsDragger
{
    private readonly Window _window;
    private Point _dragDelta;

    public WindowsDragger(Window window)
    {
        _window = window;

        _window.MouseLeftButtonDown += MouseLeftButtonDown;
        _window.MouseLeftButtonUp += MouseLeftButtonUp;
        _window.MouseMove += MouseMove;
    }

    void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _dragDelta = e.GetPosition(_window);
        Mouse.Capture(_window);
    }

    void MouseMove(object sender, MouseEventArgs e)
    {
        if (Equals(_window, Mouse.Captured))
        {
            var pos = _window.PointToScreen(e.GetPosition(_window));
            var verifiedPos = CoerceWindowBound(pos - _dragDelta);
            _window.Left = verifiedPos.X;
            _window.Top = verifiedPos.Y;
        }
    }

    void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (Equals(_window, Mouse.Captured))
            Mouse.Capture(null);
    }

    private Vector CoerceWindowBound(Vector newPoint)
    {
        // Snap to the current desktop border
        var screen = WpfScreen.GetScreenFrom(_window);
        var wa = screen.WorkingArea;
        if (newPoint.X < wa.Top) newPoint.X = wa.Top;
        if (newPoint.Y < wa.Left) newPoint.Y = wa.Left;
        if (_window.Width + newPoint.X > wa.Right) newPoint.X = wa.Right - _window.Width;
        if (_window.Height + newPoint.Y > wa.Bottom) newPoint.Y = wa.Bottom - _window.Height;
        return newPoint;
    }
}

where WpfScreen is from here: How to get the size of the current screen in WPF?

Share:
12,546
Grant
Author by

Grant

Updated on June 16, 2022

Comments

  • Grant
    Grant almost 2 years

    i am trying to make a c# WPF form where i can drag it around the screen by clicking on it and moving with the mouse. the forms characteristics include being completely transparent and containing only one image. This being said the window style is none and it is not displayed in the taskbar. So essentially all you can see when the app is running is a little image - and ideally i want to be able to drag it around the desktop if i click and hold the left mouse button and move it about.

    Does anyone know a simple way i can accomplish this or have i overlooked a build in function?

    Thanks.

    • Admin
      Admin over 12 years
      Thanks a lot, i was just looking 2 Days for such an answer :)
  • Josh
    Josh about 15 years
    There is a code example in the documentation for the DragMove method that shows exactly what you're trying to do but it's literally 3 lines long - handle the MouseLeftButtonDown event of the window, call the DragMove method on the window.
  • Ed S.
    Ed S. about 13 years
    Just use MouseLeftButtonDown and no check is needed
  • Vladimir Vlasov
    Vladimir Vlasov about 10 years
    It's strange, but simple DragMove() in MouseDown event works fine, until user moves window on the top side of the desktop (about top 100px). With your solution my form can be placed wherever user wants. If anybody wants to know, WindowStyle of my WPF form is None, and OS is Windows 7.
  • StingyJack
    StingyJack about 7 years
    This just makes the window flutter (show/hide rapidly) and jumpy when targeting a specific control as a drag surface. Is there any reason why using different Forms.Cursor.Position in one method and e.GetPosition in another?
  • Agrejus
    Agrejus about 7 years
    @StingyJack the form should be targeted as a drag surface, controls such as buttons should not be allowed to drag the form. As far as using e.GetPosition vs System.Windows.Forms.Cursor.Position, you need will need to convert System.Windows.Forms.Cursor.Position to a Point. It will look something like this. this._FormMousePosition = new Point(System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y); This works, BUT the WPF form jump's when you initially click on it. this._FormMousePosition = e.GetPosition((UIElement)this); does not cause the form to jump