Development, Featured, MVVM, Silverlight, WP7

Gestures in Windows Phone 7

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.

Development, WP7

Customizing WP7 Push Notification Tiles

This entry is part 5 of 8 in the series Windows Phone 7

Although I had originally hoped to be one of the first, there are LOTs of great articles out now about how to use Push Notifications in Windows Phone 7. Instead of re-hashing information that is already readily available on the internet, this article will instead focus on some of the things that have been left out of those articles.  If you need a refresher on how Push Notifications work, I will refer you to the following excellent articles that show you how to get it done:

My situation seemed really simple – I really liked the idea of being able to publish notifications to my WP7 applications, but didn’t AT ALL like the way they looked when they got there.  As you probably already know from your reading, that the notification system, by default, gives you the ability to customize 3 aspects of a tile – the background image, application title, and a “count”, as illustrated in the picture below:

Each tile is a 173×173 block that contains the three key elements.  My issue was with that little blue circle at the top.  It’s cool how the Outlook, Phone and Text tiles have very big, easy to read information, but I found it more difficult for my eyes to read the small number in the upper-right-hand corner of the tile. Instead, I’d rather have something that looked more awesome, like this:

Untitled

I spoke with some guys from the WP7 dev team, and they confirmed that there is no way to customize the tile layout beyond what it gives you. So that meant, any customization I needed to do would have to be done using dynamically-built graphics… My reasoning is this – the device can only get 3 pieces of information, and the graphics are the most customizable of the bunch. If I take all the information that would normally be sent down as 3 separate data points and combine it into one dynamically-built image, I can make the tile look like whatever I like.

Where to begin…

I started by downloading Yochay’s excellent Windows Phone 7 Training Kit and extracting out his lab on Push Notifications.

This lab is an EXCELLENT primer on Push Notifications in WP7, and I highly recommend that you walk through it before you try doing anything else with Push. His sample got me the boilerplate code I needed to begin my customizations. I was especially happy that he extracted all of the heavy lifting related to the actual Push into a separate assembly that I could start hacking into without fear of messing up the driver or the phone application itself. 

The architecture of the sample is really straightforward – you have a phone application that registers with the Live Notification Services and a WPF-based Driver program that pushes Tile, Toast and Raw updates down to the device.  It seemed like the most straightforward path was to modify the Driver program to somehow send out custom generated background images instead of referencing some existing static ones.  Unfortunately, that’s not how the Push Notification system works.  When you send a notification to the Phone, the phone doesn’t actually receive the image – it receives a URL pointing to the image:

<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
  <wp:Tile?>
    <wp:BackgroundImage>/Images/Cloudy.png</wp:BackgroundImage>
    <wp:Count>28</wp:Count>
    <wp:Title>Moscow</wp:Title>
  </wp:Tile>
</wp:Notification>

To accommodate a pull scenario from the device, I was going to need a way for the device to request images based on some parameters.  For that, I’d need a new web site with a custom HTTP handler that built the images I needed based on those parameters – something on the order of this:

<?xml version="1.0" encoding="utf-8"?>
<wp:Notification xmlns:wp="WPNotification">
  <wp:Tile?>
    <wp:BackgroundImage>http://somehost.com/ImageBuilder.ashx?city=Moscow&temperature=28&conditions=Cloudy</wp:BackgroundImage>
    <wp:Count>28</wp:Count>
    <wp:Title>Moscow</wp:Title>
  </wp:Tile>
</wp:Notification>

Generating custom images

For this I thought of 2 approaches – one was to use the same technology that we’ve been talking about since .NET 1.1 days and use the Graphics class inside an HTTP Handler to generate images according to a set of parameters, or I could go out on a limb and utilize the power of WPF on the server-side to use XAML to layout our custom image and use Data Binding to wire up my custom data.  I chose the latter, because that’s how I roll Winking smile

I started with some code that Cori Drew pointed me at written by Laurent Bugnion (author of my most favorite MVVM Light framework) from his article Converting and customizing XAML to PNG with server-side WPF. His code sample included a library that makes short work of taking XAML from an external file and, through the setting of WPF Dependency Properties, render the XAML to a PNG based on the data values we pass in.

First, I added a web project to the sample’s solution and created a new HTTP Handler.  In here, we have to gather the information from the call to the handler to determine what we're supposed to do:

string xamlFileName = "Default";

var _parms = request.FilePath.Split(Char.Parse("/"));
var _filename = _parms[_parms.Length - 1];
var _parts = _filename.Split(Char.Parse("_"), Char.Parse("."));
var _city = _parts[0];
var _temperature = _parts[1];
var _conditions = _parts[2];

var _backgroundImage = String.Format(
    "http://{0}{1}/BackgroundImages/{2}.png",
    request.Url.Host,
    request.ApplicationPath,
    _conditions);

I tried using QueryString parameters to keep it a bit simpler, but that didn’t seem to work for me. I’m sure it was just some silly user error, but I decided to try and be a bit clever and munge the filename instead – something like http://myserver.com/ImageGenerator/10_London_Snow.tile.  Since we want to include a graphic indicating the type of weather we’re describing, I saved off all of Yochay’s images and reconstructed a URL to the static image using our good friend String.Format.

Once we know all the parameters, we need to load the XAML file from the server and call out to the replacement logic to update it’s dependency properties based on our supplied parameters.  Here’s a sample of the code I’m using to load the XAML and set these properties:

FileInfo xamlFile = new FileInfo(context.Server.MapPath(string.Format("~/XAML/{0}.xaml", xamlFileName)));

List<DependencyPropertyReplacement> replacements = null;

string[] customizeElements = new string[5]
{
    String.Format("BackgroundImage:{0}", _backgroundImage.Replace(":", "~")),
    String.Format("Temperature:{0}°", _temperature),
    String.Format("City:{0}", _city),
    String.Format("Conditions:{0}", FormatConditionsString(_conditions)),
    String.Format("LayoutRoot:Black")
};

PrepareCustomizableReplacements(customizeElements, ref replacements);

The method PrepareCustomizableReplacements and his friend MakeCustomizableReplacement use some really interesting code to attach to each of the supplied dependency properties and update them based on their type.  The code is not as clean as it could be, as we could have done some refactoring around the use of the switch statement, but for my purposes this is fine.

private void PrepareCustomizableReplacements(string[] elements,
    ref List<DependencyPropertyReplacement> replacements)
{
    if (replacements == null)
    {
        replacements = new List<DependencyPropertyReplacement>();
    }

    foreach (string nameValue in elements)
    {
        string[] nameValuePair = nameValue.Split(new char[] { ':' });

        // This cannot be handled in a generic way because the DP must be set with a value
        // of the correct type.
        switch (nameValuePair[0])
        {
            case "LayoutRoot":
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0],
                    "Background", WpfUtility.MakeSolidColorBrush(nameValuePair[1], true)));
                break;
            case "BackgroundImage":
                var _image = WpfUtility.MakeBitmapImage(nameValuePair[1].Replace("~", ":"));
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0], "Source", _image));
                break;
            case "Temperature":
            case "Conditions":
            case "City":
                replacements.Add(MakeCustomizableReplacement(nameValuePair[0], "Text", nameValuePair[1]));
                break;
        }
    }
}

private DependencyPropertyReplacement MakeCustomizableReplacement(string elementName, string propertyName, object value)
{
    DependencyPropertyReplacement replacement = new DependencyPropertyReplacement();
    replacement.ElementName = elementName;
    replacement.PropertyName = propertyName;
    replacement.Value = value;
    return replacement;
}

You can see from here that we're looping through each of the customization points that I specified in the last code sample, attaching to the specific dependency property on the XAML control, and updating their value.  There is some custom wizardry that’s going on behind the MakeBitmapImage method that I’ll talk about next.

Fun with images…

I ran into a snag trying to set the source on our Image control. As most of you probably know, we always preach that “anything you can do in XAML you can do in code”, which of course is true, but we don’t necessarily say how easy it’s going to be to create a code equivalent. Take the Image control for example.  It’s really easy for me to set the image up using something like this in XAML:

<Image Source=”MyImage.jpg” />

Now you know that we’re not actually setting the source of the Image object to a string value of “MyImage.jpg” right? We’re creating an Image object and loading it up from the image stored on disc specified in the path provided.  WPF has a really nice set of built-in ValueConverter objects that make things really easy for us to work with “magic strings”.  In my case, I had to do things a bit more manually:

public static object MakeBitmapImage(string filename)
{

    WebClient webClient = new WebClient();
    byte[] imageContent = webClient.DownloadData(filename);

    MemoryStream memoryStream = new MemoryStream(imageContent);

    BitmapImage imageSource = new BitmapImage();
    imageSource.CacheOption = BitmapCacheOption.None;
    imageSource.BeginInit();
    imageSource.StreamSource = memoryStream;
    imageSource.EndInit();

    if (imageSource.CanFreeze)
        imageSource.Freeze();

    return imageSource;
}

You'll first notice that we have to actually fetch the image from the web ourselves. Once we have the image, we need to load it into a BitmapImage object from which we can then assign to the Image.Source dependency property.  The last snag I ran into related to the Freezing of certain properties before you can assign them.  As it turns out, you need to “freeze” BitmapImage objects before you can assign them as a source for an ImageObject due to some interesting thread ownership issues.  I won’t go into detail here, but there are some nice references on StackOverflow and MSDN to help you understand the whys and wherefores.

Once I had the image created, Laurent’s code sample just writes it to the output stream and we’re golden.

    try
    {
        using (Stream stream = File.OpenRead(xamlFile.FullName))
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                XamlToPngConverter converter = new XamlToPngConverter();
                converter.Convert(stream, 173, 173, memoryStream, replacements);

                // set the content type
                context.Response.ContentType = "image/png";
                memoryStream.WriteTo(context.Response.OutputStream);
            }
        }
    }
    catch (Exception ex)
    {
        throw new HttpException(404, "Image not found:" + xamlFileName, ex);
    }

At this point we have a working dynamic image generator. Cool, isn’t it?  Now all we have to do is wire it up to the Driver program so that the phone knows where to go grab the correct tile image.

Sending the right tile

Luckily, the rest of the changes were really minimal. Although there were a few tweaks to other parts of the driver program, the key change is in the definition of the URI:

private void sendTile()
{
    //TODO - Add TILE notifications sending logic here
    string weatherType = cmbWeather.SelectedValue as string;
    int temperature = (int)sld.Value;
    string location = cmbLocation.SelectedValue as string;
    List<Uri> subscribers = RegistrationService.GetSubscribers();
    var _uri = String.Format("http://localhost/ImageGenerator/{0}_{1}_{2}.tile", location, temperature, weatherType);
    ThreadPool.QueueUserWorkItem((unused) => notifier.SendTileNotification(
        subscribers, "PushNotificationsToken",
        _uri, temperature, weatherType.Replace("-", " "), OnMessageSent));
}

Once we had the proper URI for the image (one based on all the parameters we needed to decode) we only had one more important change to make – this time in the NotificationSenderUtility library.

In here, the expected behavior for sending a tile message is to send all three parts of the data – count, title and image.  In our case, we DON’T want the count coming across because it will just mess up our UX.  To accommodate, I just commented out the line that sets the Count value in the outgoing XML and we were good to go:

private static byte[] prepareTilePayload(string tokenId, string backgroundImageUri, int count, string title)
{
    MemoryStream stream = new MemoryStream();

    XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
    XmlWriter writer = XmlTextWriter.Create(stream, settings);
    writer.WriteStartDocument();
    writer.WriteStartElement("wp", "Notification", "WPNotification");
    writer.WriteStartElement("wp", "Tile", "WPNotification");
    writer.WriteStartElement("wp", "BackgroundImage", "WPNotification");
    writer.WriteValue(backgroundImageUri);
    writer.WriteEndElement();
    writer.WriteStartElement("wp", "Count", "WPNotification");
    //writer.WriteValue(count.ToString());
    writer.WriteEndElement();
    writer.WriteStartElement("wp", "Title", "WPNotification");
    writer.WriteValue(title);
    writer.WriteEndElement();
    writer.WriteEndDocument();
    writer.Close();

    byte[] payload = stream.ToArray();
    return payload;
}

With these changes in place, everything was wired up and worked exactly as I had hoped it would Smile

Now what?

It’s still not perfect – there is some code cleanup I’d like to do, and the images with text added to them don’t show up as crisp and clear as if we’d used the push infrastructure the way it was designed, but it’s a good start.  If you have any questions, post a comment and lets discuss it.  I’ve posted my code sample on Skydrive, so it should be easy to find:

Happy Push Notification-ing!

Dallas, Development, Events, Texas, user group, WP7

Silverlightpalooza! WP7 and Silverlight DevCamp

Come Join Us for two day s of Code and Fun with Silverlight and Windows Phone 7!

wp7microsoft-silverlight We will start Friday June 18th with a walkthrough of the tools and some key skills to get you started.  The goal is to provide a foundation to enable groups to build dynamic Windows Phone 7 applications using Microsoft Silverlight.  How we structure the training and focus points will depend on how attendees answer a few questions when they sign up. At the end of the day on Friday, you will join with a few of your peers to start collaborating on your own WP7 or Straight-up Silverlight application to work on and present to the other groups at the end of Saturday. 

Saturday June 19th, we build, build, build (you can start Friday night if you want but you will need to do that off site).  Mentors will be on hand to answer questions and add clarity to problem spots.

At the end of Saturday, the groups will have an opportunity to show what they built and bring it all together.  Before we all go home, we’ll have some cool giveaways.

Lunch will be provided both days!

You can get more information about this event at http://silverlightpalooza.dynamitesilverlight.com/ or register right here, right now!

Register for DFW Silverlight and WP7 DevCamp (Silverlightpalooza) in Irving, TX  on Eventbrite

Development, Windows, WP7

WP7 Part 3: Navigation

This entry is part 3 of 8 in the series Windows Phone 7

NOTE: Since the first article was released, the WP7 tools have been updated with an April Refresh. The original post has been updated to reflect the proper download to get the April CTP-friendly code and we will use that as a starting point for this post.

OK – I have a confession to make. Actually, it’s more of something I have to admit – I made a mistake. In picking NerdDinner as the foundation for this blog series, I figured that having all kinds of screwball data in it would be perfectly OK since it wasn’t a “real” application, and I didn’t want to worry about working with actual live sites. That turned out to be a mistake. Although the NerdDinner site is a great idea, and a great learning tool for ASP.NET MVC developers, the data is *really* bad, and not something I want to continue working with for this series. SO… I’ve re-written the application from NerdDinner to use Community Megaphone, an event management and listing site maintained by my friend and collegue G. Andrew Duthie (a.k.a. DevHammer). I’ve also simplified things a bit and removed the repository pattern (at least for now) in favor of a more traditional approach, that we can look later at refactoring when we introduce an IoC container and begin to do DI, etc. So, for now, let’s just pretend that we’ve been working with CM all along, shall we?

Out of the box, the Windows Phone 7 tools give you a pretty good starting place for your application. The List template is based on the MVVM pattern, includes some sample code to help you better visualize your solution, and two pages to get you started: main page (list of items) and details page (details for an item). In this post we�ll explore the page navigation options available to the WP7 developer, starting with the OOB experience.

The sample application uses an, um� interesting approach to navigating from one page to another. The idea is simple: choose an item from the main list, show a cool page transition animation, then navigate to the new page with the details showing up. The way they accomplish this is to trap the left mouse button up event, store off the currently selected item, and start a page transition (i.e. storyboard). When the animation is complete, the main page uses the built-in Navigation framework to navigate the application to the new page. For that details page to get its data context, the main page (remember that he�s still in control until the current method exits) grabs hold of the root visual in the details page and sets that�s page�s DataContext attribute to the saved off currently selected item in the list.

hmmm.

I don�t know about you, but this somehow just plain bothers me. I realize that there are always several ways to skin a cat, but this one seems particularly icky to me. I don�t think it�s the job of the main page to force a data context on a details page. The details page should be told which object to use as its reference, or a key to that object perhaps, and then allowed to render itself.

To accomplish this in WP7 there are a couple of options:

  1. Continue to attach to the details page after navigating to it and send it the data on which it should operate � just do it in a slightly less icky way
  2. Send a parameter to the details page so that when it opens, it knows which object to get from the database, then it makes that stuff happen.
  3. Store the selected item into Isolated Storage (or some other caching mechanism), navigate to the new page, and then retrieve it again.

Navigation in WP7 is based on a similar framework to what you�re used to with ASP.NET. It uses a simple URI-based scheme for indicating which page in your application to load and navigate to.

Uri theUri = new Uri(�/DetailsPage.xaml�, UriKind.Relative);
NavigationContext.Navigate(theUri);

In this example, the NavigationContext loads the DetailsPage.xaml and navigates the application there using an unadorned, relative URI. Note: absolute URIs are not supported – you can’t use this mechanism to cause the built-in web browser to open a web page. There is a different technique for that which we’ll look at later. One thing you get for free with the Navigation framework is the ability to respond smartly to the Back button on the phone. After navigating to a new page, if the user presses the Back button on the phone, the application will go back to the last item in the Navigation stack. Pretty smart, eh?

OK – enough bakground, let’s go build something. In the MVVM world, the ViewModel takes the responsibility for loading itself on behalf of it’s View. In our case, we�re going to need a ViewModel that will do this for a given Event based on it’s associated Event ID. We�ll start by changing the call to the Details page to accept an Event ID as a parameter in the Navigation Context

private void PageTransitionList_Completed(object sender, EventArgs e)
{
    // Set datacontext of details page to selected listbox item
    //NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
    //FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
    //root.DataContext = _selectedItem;

    Uri theUri = new Uri("/DetailsPage.xaml?eventId=" + _selectedItem.id, UriKind.Relative);
    NavigationService.Navigate(theUri);

}

The QueryString, you say? Yes, the QueryString. Once inside the Details page, we can then use the NavigationContext again to retrieve the associated eventId and load the ViewModel with the right data:

void DetailsPage_Loaded(object sender, RoutedEventArgs e)
{
    int eventId = 0;

    //TODO: put some better error handling in here
    Int32.TryParse(NavigationContext.QueryString["eventId"], out eventId);

    // Set the data context of the listbox control to the sample data
    vm.View = this;
    DataContext = vm;
    vm.LoadFromId(eventId);
}

The view model can then use our same tricks from before to load the specific Event:

public void LoadFromId(int eventId)
{
    var catalog = CMEventsEntities.Instance;

    //var query = from e in catalog.ApprovedEvents
    //            where e.id == eventId
    //            select e;
    //DataServiceQuery dsq = query as DataServiceQuery;

    DataServiceQuery dsq = catalog.ApprovedEvents
        .AddQueryOption("$filter", "id eq " + eventId);

    dsq.BeginExecute(new AsyncCallback(a =>
    {
        var result = dsq.EndExecute(a).FirstOrDefault();

        View.Dispatcher.BeginInvoke(() =>
        {
            Item = result;
            NotifyPropertyChanged("Item");
            NotifyPropertyChanged("PageTitle");
        });

    }), null);
}

Note that this time, I was unable to get the typical LINQ query to retrieve the data I wanted, so I reverted to the AddQueryOption method of the DataServiceQuery to get what I needed from the OData service. I think this might be due to a bug in the pre-release version of the OData provider I’m using, becuase I can’t see any reason why the straight-up LINQ syntax shouldn’t work. Anyway, the pattern is the same as before: create a DataServiceQuery based on the data you want to retrieve, call BeginExecute, when the results come back they get processed on the UI thread in order to update the UI (note to self: I should probably create a code snippet for this so I don’t have to keep typing it all the time…) I’m also directly raising the NotifyPropertyChanged event for both the Item (our target Event) and the PageTitle property (which is based on the selected Item). That way, our UI will stay in sync with the data we’re maintaining in the ViewModel.

After this, and a little bit of Data Binding magic, our UI is populated and we have our details page!

One thing left to do related to Navigation – that pesky URL. As I mentioned before, you can’t use the built-in Navigation Framework to open a Web Browser to a given URL. You can try it if you want to – I’ll wait here… Didn’t work did it? Here’s what you can do:

  • Web Browser Control: Create a separate page that hosts a web browser control, and navigate there using the target URL as a QueryString property. When the web browser page loads, you can navigate the web browser control bring up the page you want. This is an OK option, but depends on what you’re really trying to accomplish/
  • WebBrowserTask: Using the WP7 Task infrastructure (I know, we haven’t covered that yet), you can launch the phone’s default web browser on a given URL. This is the method I’ll choose for this application, and I’ll show the code that makes it work.

We’ll be covering the Tasks infrastructure in more detail as part of a later post, but for now, just go with me…

There are many Task objects in the Windows.Phone.Tasks namespace – they are all designed to do a specific type of thing: launch some process to either display information, or capture information. The one we care about here, is the WebBrowserTask object. It’s whole purpose in life is to launch the phone’s built-in web browser to a specific URL. That being said, it couldn’t be easier to use. For our application, we’re displaying the event URL in a HyperlinkButton and capturing the Click event:


Once this event fires, we create an instance of the WebBrowserTask object, set it’s URL and call the Show() method to get the job done.

private void HyperlinkButton_Click(object sender, RoutedEventArgs e)
{
    WebBrowserTask task = new WebBrowserTask();
    task.URL = vm.Item.eventUrl;
    task.Show();
}

Clicking on the link launches the web browser and we can see the event in all of its default glory. Pressing the Back button takes us back to the details page, and back again will take us back to the home page.

That’s it for this post. In future posts, I’m planning to add an application bar that will allow us to modify our query parameters controlling what events we show in the main list, and hopefully integrate the Bing Map engine to show more information about the selected event.

Development, Videos

How Do I: Code Navigation Improvements in VS2010

This entry is part 2 of 5 in the series How Do I?

Exploring code is a great way to learn, but CTRL-F isn’t the only way to get around. Visual Studio 2010 adds some interesting new code navigation features to help developers better understand their code and find what they need quickly and easily. in this video, I explore a few of the new features and show you how to be more productive editing code with Visual Studio 2010.

To see all the videos in this series, check out my channel on Vimeo