Search code examples
c#drag-and-dropwindows-phonewindows-phone-8.1uielement

Delay in drag/drop of UIElement in Windows Phone 8.1


I'm using the ManipulationDelta event handler to drag and drop a simple ellipse in a canvas across the screen. I'm using the standard approach posted online in several places. Following is the code in my event handler:

Ellipse dragableItem = sender as Ellipse;
TranslateTransform translateTransform = dragableItem.RenderTransform as TranslateTransform;
double newPosX = Canvas.GetLeft(dragableItem) + translateTransform.X + e.Delta.Translation.X;
double newPosY = Canvas.GetTop(dragableItem) + translateTransform.Y + e.Delta.Translation.Y;

if (!isCanvasBoundary(newPosX, TestCanvas.ActualWidth - dragableItem.ActualWidth, 0))
      translateTransform.X += e.Delta.Translation.X;

if (!isCanvasBoundary(newPosY, TestCanvas.ActualHeight - dragableItem.ActualHeight, 0))
      translateTransform.Y += e.Delta.Translation.Y;

The drag and drop operation works fine, but there's a nasty delay of around 1 second between when the user begins dragging to when the ellipse actually changes its position. I can see by printing to the Debugger that the event handler itself finishes executing almost instantly, so I'm guessing it has something to do a pre-programmed refresh rate for all UIElements on the screen that's causing this delay?

Is there anyway around this issue?


Solution

  • I had the same problem some time ago. I guess that the delay is to decide whether the gesture is drag or tap. It's hard to touch a screen without any accidental drag.

    To eliminate this lag, you can use PointerMove and PointerPressed events. Here's my example. You have canvas with two ellipses which can be dragged without any delay.

    XAML

    <Grid>
        <Canvas x:Name="Board" PointerMoved="Canvas_PointerMoved" Background="Black">
            <Ellipse Width="64" Height="64" Fill="Red"
                     Canvas.Left="32" Canvas.Top="128" PointerPressed="Ellipse_PointerPressed"/>
            <Ellipse Width="96" Height=" 96" Fill="Blue"
                     Canvas.Left="128" Canvas.Top="16" PointerPressed="Ellipse_PointerPressed"/>
        </Canvas>
    </Grid>
    

    As you can see, I'm handling PointerMoved event in canvas and PointerPressed event in ellipses. It's important that the background of the canvas is not transparent to handle touch events.

    C#

    public sealed partial class MainPage : Page
    {
        UIElement draggedItem = null;
        Point offset;
    
        public MainPage()
        {
            this.InitializeComponent();
            this.NavigationCacheMode = NavigationCacheMode.Required;
        }
    
        private void Ellipse_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            draggedItem = sender as UIElement;
            offset = e.GetCurrentPoint(draggedItem).Position;
        }
    
        private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            if (draggedItem == null)
                return;
    
            Point dragPoint = e.GetCurrentPoint(Board).Position;
            Canvas.SetLeft(draggedItem, dragPoint.X - offset.X);
            Canvas.SetTop(draggedItem, dragPoint.Y - offset.Y);
        }
    }
    

    I think the code is quite simple and understandable. I use PointerPressed to decide which object is dragged. I'm also calculating some offset, because we want to move the object relative to the point where user touches.

    screenshot