xamlwinui-3winui

Correct way of setting an elements position in relevance to another element or pointer


What is the correct approach to set the position of a object in relevance to the pointer? I have tried

private void TextBlockPressed(object sender,   PointerRoutedEventArgs e)
{
  var currentPoint = e.GetCurrentPoint(sender as UIElement);
  Canvas.SetLeft(element, e.Position.X);
}

Solution

  • Let me show you a basic example which lets you drag a Rectangle on a Canvas:

    *.xaml

    <Canvas
        x:Name="CanvasControl"
        Background="Transparent"
        PointerMoved="CanvasControl_PointerMoved"
        PointerPressed="CanvasControl_PointerPressed"
        PointerReleased="CanvasControl_PointerReleased">
        <Rectangle
            Width="100"
            Height="100"
            Fill="SkyBlue"
            PointerPressed="Rectangle_PointerPressed" />
    </Canvas>
    

    *.xaml.cs

    private UIElement? DraggingUIElement { get; set; }
    
    private Point DeltagStartPoint { get; set; }
    
    private void Rectangle_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        DraggingUIElement = sender as UIElement;
    }
    
    private void CanvasControl_PointerReleased(object sender, PointerRoutedEventArgs e)
    {
        DraggingUIElement = null;
    }
    
    private void CanvasControl_PointerPressed(object sender, PointerRoutedEventArgs e)
    {
        if (sender is not Canvas canvasControl)
        {
            return;
        }
    
        DeltagStartPoint = e.GetCurrentPoint(canvasControl).Position;
    
    }
    
    private void CanvasControl_PointerMoved(object sender, PointerRoutedEventArgs e)
    {
        if (DraggingUIElement is null ||
            sender is not Canvas canvasControl)
        {
            return;
        }
    
        var point = e.GetCurrentPoint(canvasControl).Position;
        double deltaX = point.X - DeltagStartPoint.X;
        double deltaY = point.Y - DeltagStartPoint.Y;
    
        double elemnetX = Canvas.GetLeft(DraggingUIElement);
        double elementY = Canvas.GetTop(DraggingUIElement);
    
        double newX = elemnetX + deltaX;
        double newY = elementY + deltaY;
    
        Canvas.SetLeft(DraggingUIElement, newX);
        Canvas.SetTop(DraggingUIElement, newY);
    
        DeltagStartPoint = point;
    }
    

    UPDATE

    If you want to center the rectangle on the pointer when the rectangle is clicked:

    private void Rectangle_PointerPressed(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        if (sender is not UIElement uiElement)
        {
            return;
        }
    
        DraggingUIElement = uiElement;
        var positionOnDraggingUIElement = e.GetCurrentPoint(DraggingUIElement).Position;
        double draggingElementCenterX = DraggingUIElement.ActualSize.X / 2;
        double draggingElementCenterY = DraggingUIElement.ActualSize.Y / 2;
    
        var delta = new Point(
            draggingElementCenterX - positionOnDraggingUIElement.X,
            draggingElementCenterY - positionOnDraggingUIElement.Y);
        Canvas.SetLeft(DraggingUIElement, Canvas.GetLeft(DraggingUIElement) - delta.X);
        Canvas.SetTop(DraggingUIElement, Canvas.GetTop(DraggingUIElement) - delta.Y);
    }