Dragging a WPF Window Around

Wednesday, December 02, 2009 / Posted by Luke Puplett /

This short article shows how to drag a WPF application window around your desktop when you have removed the stock Microsoft Windows chrome.

Applications using WPF and having a particularly stylistic look and feel often don’t sit well with the standard Windows chrome supplied by the operating system. It’s easy to remove this chrome, but once it’s gone your users lose the ability to move your application window around.

Here’s how to hook up a region (in this case, a grid) to serve as a handle so as long as the mouse is held down and dragging around, the window moves with it.

First, hook up a single MouseLeftButtonDown handler in your XAML on the element you wish to use.

<Grid Grid.Row="0" MouseLeftButtonDown="Grid_MouseLeftButtonDown" >

The codebehind file for the Window looks like this – see notes at the bottom.

    public partial class Window1 : Window
    {
        private System.Drawing.Point _windowMoveMouseStart;
        private double _windowMoveStartTop;
        private double _windowMoveStartLeft;

        public Window1()
        {
            this.InitializeComponent();

            // Insert code required on object creation below this point.
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            UIElement handle = sender as UIElement;
            if (handle == null)
                return;

            _windowMoveMouseStart = System.Windows.Forms.Control.MousePosition;
            _windowMoveStartTop = this.Top;
            _windowMoveStartLeft = this.Left;

            handle.MouseMove += Handle_MouseMove;
            handle.CaptureMouse();
        }

        void Handle_MouseMove(object sender, MouseEventArgs e)
        {
            UIElement handle = sender as UIElement;
            if (handle == null)
                return;

            if (e.LeftButton == MouseButtonState.Released)
            {
                handle.MouseMove -= Handle_MouseMove; // Detach listener on mouse up.
                handle.ReleaseMouseCapture();
            }
            else
            {
                var smp = System.Windows.Forms.Control.MousePosition;
                var distanceX = smp.X - _windowMoveMouseStart.X;
                var distanceY = smp.Y - _windowMoveMouseStart.Y;

                this.Left = _windowMoveStartLeft + distanceX;
                this.Top = _windowMoveStartTop + distanceY;
            } 
        }
    }

At the top is a System.Drawing.Point which means you need to add a reference to System.Drawing as well as System.Windows.Forms to get access to the Control.MousePosition static property – unless you know of a better way to get at non-relative mouse data.

CaptureMouse

Key to this is the UIElement.CaptureMouse() method which sets the eventing system to continue firing even when the mouse is outside the bounds of the element. Without this the mouse can ‘'skid off’ the handle when its moved too fast – too fast being quite slow actually.

If a mouse move is captured and the button isn’t down, we disconnect all the mechanics previously setup. Since the mouse move should always be captured, even when its not over the original handle, the mechanics should always get detached.

Windows 7 Aero Shake

Not sure if this will then trigger the Windows 7 shake feature...

Labels: , , ,

0 comments:

Post a Comment