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