Reactive Extensions responding to UI events by ThinqLinq

Reactive Extensions responding to UI events

One of the great things about the Reactive Extensions is that they allow you to express rather complex interactions simply. For this example, we’ll consider the mouse drag drop operation in Silverlight. Note: The identical code works in both the web based Silverlight and the Windows 7 phone. If you want to download the phone version of this code, it is available in C# or VB.

One of the indicators of simplicity is if you can explain a concept to your mother. How would you explain drag-drop to your mother?  It may go something like this:

  • Record the start location when you press the mouse button down.
  • While you are moving the mouse, record the end location until you let the mouse button up.
  • Calculate the difference between the start and end locations and move the image you dragged accordingly.

Now, let’s see how we can do this in code. The beauty of the Reactive programming model is that we can compose multiple expressions together in a concise manner. Here’s how we accomplish the above process:

Dim q = From startLocation In mouseDown
        From endLocation In mouseMove.TakeUntil(mouseUp)
        Select New With {
            .X = endLocation.X - startLocation.X,
            .Y = endLocation.Y - startLocation.Y

As you can see, this code reads nearly the same as the description you gave to your mother. It is actually a bit more concise than the slightly more verbose description.

At this point we have a couple details to wrap up. First, we need to declare the variables for mouseDown, mouseMove and mouseUp that we used above. We do this by using RX to subscribe to the events as discussed in this post.

Dim mouseDown = From evt In Observable.FromEvent(Of MouseButtonEventArgs)(image, "MouseLeftButtonDown")
                Select evt.EventArgs.GetPosition(image)
Dim mouseUp = Observable.FromEvent(Of MouseButtonEventArgs)(Me, "MouseLeftButtonUp")
Dim mouseMove = From evt In Observable.FromEvent(Of MouseEventArgs)(Me, "MouseMove")
                Select evt.EventArgs.GetPosition(Me)

While we’re here, notice that we are grabbing the MouseLeftButtonDown event of the image. However, we track the mouseMove and mouseUp on the form itself. We could use the MouseMove and MouseLeftButtonUp events of the image, but if we try to move too fast, the time Silverlight takes to calculate that the mouse is moving on the image rather than the canvas can mean that your movement is detected off of the image before you’ve been able to move the image. Tracking on the form itself drastically increases performance and reduces the possibility that you will move off of the image too soon.

The last thing we need to do is to move the image to the new location. In this sample, we placed the image on a Canvas. We just need to use the distance we recorded in our query and subscribe to the observable with an action that moves the image:

                Canvas.SetLeft(image, value.X)
                Canvas.SetTop(image, value.Y)
            End Sub)

If you want to see this code in action, the VB version is available in the WPF samples and WP7 samples on the download page. The C# sample is in the Silverlight RX samples and WP7 samples also on the download page.

Posted on - Comment
Categories: VB Dev Center - Rx -
comments powered by Disqus