Search code examples
wpfcontextmenumovedragdrop

Set mouse position to center of title in borderless window when clicking move in context menu


I search for a solution to the following problem: For a nice look I use a borderless window, so I have created a title area for this window (it's a Grid).

  <Grid x:Name="rootGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{DynamicResource BackgroundColor}" >
    <Grid.ContextMenu>
        <ContextMenu>
            <MenuItem x:Name="cmiVerschieben" Header="Verschieben" Click="cmiVerschieben_Click"/>
        </ContextMenu>
    </Grid.ContextMenu>
    <!-- ... -->
</Grid>

Now I added a context menu to the title bar like the most applications have (Close, Maximize, Minimize, Move ...).

The simple commands are not a problem, but for the "Move"-Entry I have to move my mouse cursor from the current position to the center of my title grid.

I tried it in cmiVerschieben_Click with rootGrid.Focus(); and rootGrid.CaptureMouse();, but both don't set my cursor to the rootGrid.

Why I want to do this? In many other applications when I click the "Move" context menu item, the mouse is moved to the center of the title window.

I removed the unnecessary event handler from my code here.


Solution

  • First, you will need some interop code to get and set the current mouse position on screen. Take a look at these related questions as reference: Get mouse position. Set mouse position.

    [DllImport("User32.dll")]
    private static extern bool SetCursorPos(int x, int y);
    
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetCursorPos(ref Win32Point pt);
    
    [StructLayout(LayoutKind.Sequential)]
    internal struct Win32Point
    {
       public int X;
       public int Y;
    }
    
    private static Point GetMousePosition()
    {
       Win32Point w32Mouse = new Win32Point();
       GetCursorPos(ref w32Mouse);
    
       return new Point(w32Mouse.X, w32Mouse.Y);
    }
    

    Then you can calculate the postion difference to your rootGrid and set the new mouse position, as well as a different mouse cursor icon.

    private void CmiVerschieben_OnClick(object sender, RoutedEventArgs e)
    {
       var positionOnRootGrid = Mouse.GetPosition(rootGrid);
       var xDifference = (int)(positionOnRootGrid.X - rootGrid.ActualWidth / 2);
       var yDifference = (int)(positionOnRootGrid.Y - rootGrid.ActualHeight / 2);
       var absoluteMousePosition = GetMousePosition();
    
       var absoluteXPosition = absoluteMousePosition.X - xDifference;
       var absoluteYPosition = absoluteMousePosition.Y - yDifference;
    
       // Set the position in the center of the root grid
       SetCursorPos(absoluteXPosition, absoluteYPosition);
    
       // Set the mouse cursor icon for roorGrid
       rootGrid.Cursor = Cursors.SizeAll;
    }
    

    Of course, you the have to handle dragging the window and resetting to cursor later.