How to await a drag operation

[This post is part of a series How to await a storyboard, and other things]

 

In my app, I want to await a drag operation. Here’s how I’d like to await it:
  

 Private Async Sub rectangle1_PointerPressed(sender As Object,
e As PointerRoutedEventArgs) Handles rectangle1.PointerPressed
Await DragAsync(rectangle1, e)
End Sub

 

Here below is my implementation for win8, for dragging a UIElement on a canvas. I didn't bother supporting a cancellation-token because it's easy for the user to cancel: just by letting go!

 

    Function DragAsync(shape As UIElement, origE As PointerRoutedEventArgs,

                       Optional progress As IProgress(Of Point) = Nothing) As Task

 

        Dim tcs As New TaskCompletionSource(Of Point)

        Dim origPos = New Point(Canvas.GetLeft(shape), Canvas.GetTop(shape))

        Dim origPt = origE.GetCurrentPoint(Nothing).Position

        Dim lambdaMoved As PointerEventHandler = Nothing

        Dim lambdaReleased As PointerEventHandler = Nothing

 

        lambdaMoved = Sub(s, e)

                          Dim pt = e.GetCurrentPoint(Nothing).Position

                          If Not progress Is Nothing Then progress.Report(pt)

                          Canvas.SetLeft(shape, origPos.X + pt.X - origPt.X)

                          Canvas.SetTop(shape, origPos.Y + pt.Y - origPt.Y)

                      End Sub

 

        lambdaReleased = Sub(s, e)

                             RemoveHandler shape.PointerMoved, lambdaMoved

                             RemoveHandler shape.PointerReleased, lambdaReleased

                             shape.ReleasePointerCapture(origE.Pointer)

                             tcs.SetResult(e.GetCurrentPoint(Nothing).Position)

                         End Sub

 

        shape.CapturePointer(origE.Pointer)

        AddHandler shape.PointerMoved, lambdaMoved

        AddHandler shape.PointerReleased, lambdaReleased

        Return tcs.Task

    End Function

 

Actually, let’s make it fancy with a rubber-band for the drag operation, relying on the fact that we wrote DragAsync to report back its progress:
  

Private Async Sub rectangle1_PointerPressed(sender As Object,

                e As PointerRoutedEventArgs) Handles rectangle1.PointerPressed

    Dim origPt = e.GetCurrentPoint(Nothing).Position

    Dim rubber As New Shapes.Line With

              {.X1 = origPt.X, .Y1 = origPt.Y,

               .Stroke = New SolidColorBrush(Colors.Red),

               .Visibility = Xaml.Visibility.Collapsed}

    canvas1.Children.Add(rubber)

    Dim p As New Progress(Of Point)(Sub(pt)

                                        rubber.X2 = pt.X : rubber.Y2 = pt.Y

                                        rubber.Visibility = Visibility.Visible

                                    End Sub)

    Await DragAsync(rectangle1, e, p)

    canvas1.Children.Remove(rubber)

End Sub