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



                         End Sub



        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}


    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)


End Sub