A friend contacted me yesterday asking me how to enable some sort of side-to-side scrolling of images, similar to the way to that the Pictures Viewer works. He looked at taking a ListBox, turning it on its side and just scrolling sideways, but it didn’t give him the “feel” that he wanted.  I thought it would be a fun diversion from the other stuff I was doing to use this request as an excuse to start looking at the gesture support in WP7.

As it turns out, doing this was very easy, and only required the addition of 2 libraries – both from the XNA Framework for WP7.  I’ll use this blog post to document how I did it, and hopefully come back later and add some snazzy transitions and other stuff in the future.  I used my Netflix Browser application as the inspiration for this application, so if you’re familiar with what I did there the data access portion will make total sense.  I also used MVVM Light, which is my current favorite MVVM framework, although using MVVM is not necessary for this type of demonstration.

In this application, I have one main page that displays the BoxArt from the currently selected movie. As you swipe left and right, the application swaps out the images, in order, to create a “previous/next” type of effect.  I haven’t added any animations or anything yet – hopefully that will come in a future version. The magic here is all in the ViewModel and the Silverlight Manipulation Events – so lets dive in and take a look…

The ViewModel

We start off by creating a simple view model with two properties:

  • Items – this is a collection of the movies that we’re tracking. In my code I limit this to 20 movies just so things don’t take too long to load.
  • CurrentItem – this is the currently selected item from the Items collection that the UX will data bind to. As necessary, this item switches its source from one movie to the next, with the expectation that the UX will automatically update to reflect the newly selected movie.

I’m also tracking an internal variable, SelectedIndex, that will help us keep track of where the CurrentItem is in the list of Items.  We use logic to constrain this index to the bounds of the Items list so we don’t get any out-of-range or out-of-bounds types of exceptions.

Since the ViewModel is responsible for loading up our data, we need to add that next.  I’ve shown the new OData library before – this time, we’re also responding to the LoadCompleted event on our DataServiceCollection<T> so that we can initialize the SelectedIndex property and the CurrentItem property to correspond with the first item in the list.

private void LoadRuntimeData()
{
    Uri serviceUri = new Uri("http://odata.netflix.com/catalog", UriKind.Absolute);
    NetflixCatalog catalog = new NetflixCatalog(serviceUri);

    Uri queryUri = new Uri("/Titles?$filter=Rating eq 'PG' and ReleaseYear eq 1988&$orderby=AverageRating desc&$top=20", UriKind.Relative);

    _items = new DataServiceCollection<Title>(catalog);
    _items.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(_items_LoadCompleted);
    _items.LoadAsync(queryUri);
}

private void _items_LoadCompleted(object sender, LoadCompletedEventArgs e)
{
    this.SelectedIndex = 0;
    this.CurrentItem = this.Items[this.SelectedIndex];
}

Once the data is loaded, the method that does the heavy lifting here is called ChangeSelectedIndex and takes an integer (+1 or –1) as a parameter.

internal void ChangeSelectedIndex(int modifier)
{
    // validate input
    var selectedIndex = this.SelectedIndex;
    if (selectedIndex + modifier < 0)
        return;
    if (selectedIndex + modifier >= this.Items.Count)
        return;

    // change the index and reset the current item
    this.SelectedIndex += modifier;
    this.CurrentItem = this.Items[this.SelectedIndex];
}

This parameter is used to track the direction of movement within the Items collection and ultimately determines which item needs to be displayed. We do some bounds checking to make sure that we’re staying within the range of the Items collection, but other than that we use it just to find the correct item and set it to the CurrentItem property.

How does this method get called?  We use the MVVM Light Messaging infrastructure to make that happen.  In the ViewModel constructor, I add one line of code to listen for the right message:

Messenger.Default.Register<SelectionChangedMessage>(
    this, (message) => ChangeSelectedIndex(message.Modifier));

At this point, everything is wired up and we're ready to move on to the UX

The User Experience

Once the ViewModel is created, we need to build the UX.  This time, instead of a ListBox to display all the downloaded movies, we’re using only an Image control that’s been configured to respond to user gestures. In Silverlight for WP7, we do that through 3 different event handlers:

  • ManipulationStarted – user is initiating a gesture (pan, flick, etc)
  • ManipulationDelta – user gesture is “in progress”
  • ManipulationCompleted – user has completed gesture (removed fingers, etc)

Each of them are valuable in their own right, but for our purposes, we only want to track the times that a user completes a gesture so that we can respond to it.  To make sure that I captured the gesture from anywhere on the page, I added an event handler to the PhoneApplicationPage object (the root of our XAML document). 

For the next part, Silverlight itself does not contain all the framework bits to do what we want it to.  For additional help, we’re going to bring in 2 of the XNA libraries.  For those of you playing along at home, you’ll need to add 2 references:

  • Microsoft.Xna.Framework
  • Microsoft.Xna.Framework.Input.Touch

These libraries serve to extend our gesture-handling capabilities allowing us to capture all the data related to these gestures and use them in our applications.  Without these references included, we’d get compile errors saying that certain types we were trying to access were not defined in the project, and suggest that we were missing some project references.

Now that the references are in place, we can finish configuring our gesture listener.  Inside the codebehind for the page, we do a little bit of testing to make sure we are tracking the right kind of gesture, and send the processing on to the Messaging infrastructure.

private void Image_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
    while (TouchPanel.IsGestureAvailable)
    {
        // Read and respond to the current gesture
        GestureSample gesture = TouchPanel.ReadGesture();

        if (gesture.GestureType == GestureType.Flick)
        {
            // determine direction
            var modifier = gesture.Delta.X > 0 ? -1 : 1;

            // send message to ViewModel
            Messenger.Default.Send<SelectionChangedMessage>(new SelectionChangedMessage(modifier));
        }
    }
}

In this code, we first check to make sure that we’re actually responding to a real gesture using the IsGestureAvailable property of the TouchPanel object (yep – this is one of those XNA objects I was telling you about).  To limit the scope of what gestures we want to work with, we can also add the following line to the constructor to tell the TouchPanel that we’re only interested in Flick gestures:

TouchPanel.EnabledGestures = GestureType.Flick;

Once we’ve determined that we’re working with a Flick gesture, we have to figure out whether the user was flicking to the left, intending to go to the next picture, or flicking to the right, intending to go back.  Luckily for us, that’s really easy to do with the GestureSample class’s Delta property.  The delta we want is along the X axis, tracking left to right or right to left movement.  If  the GestureSample.Delta.X value is positive, that means the user flicked from left to right, indicating that they wanted to move back in the picture stack. If the GestureSample.Delta.X value is negative, the user flicked from right to left and wants to go to the next picture (I know, this sounds upside down, but really – it does work).

When we have the direction the user wanted to go, we can set the index modifier to either +1 (next picture) or –1 (previous picture) and send it to the VM.  We do this through the Messaging infrastructure provided by MVVM.  I created a simple class called SelectionChangedMessage that has only one int property, Modifier, to express that value.  Once dumped into the message bus, the ViewModel will pick it up, run the code we wrote earlier, and switch out the current picture with the next one.  Magic!

At this point you might be saying to yourself "gosh Chris, I thought with MVVM we weren't supposed to have any code in our codebehind files?” To that I say "nay, nay". Code in the codebehind is perfectly acceptable so long as what you're doing relates to the UX itself. If you're manipulating business objects, or doing something related to business or data access logic, then you definitely need to work in the VM.

Summary

Adding gesture support to your WP7 application is really easy – it’s a bit trickier to make some nice looking transitions between elements, or within gestures. I hope to add to this post later with some tips on how you can do that. For now, you can download the code from this post using the link below.

2 thoughts on “Gestures in Windows Phone 7

  1. I had to do the same thing to show Photos in my WP7 app. I was able to use the PivotControl, binding my Photos to the ItemSource. Worked out pretty well with NO code.

Comments are closed.