WP7Contrib – Bing Service Wrapper Part II – Route

In the previous post we looked at the Location Service and how you can use the WP7C REST API Wrapper to make your app location aware. We also looked in some detail about the structure of the sample app for bing maps covering off how we use funq and to setup the scaffolding in the bootstrapper. Location is a simple but effective way of introducting geo location experiences into your app. Routes add an extra dimension to your app. If you have used this REST API then you will know that it’s not as simple as it should be.

For a deep dive into how the location bits work under the covers checkout Ollie’s post.

What we’ve done is to simplify this process so the WP7C is doing all the heavy lifting for you, making it a trivial task to incorporate these experiences into you app. In this post I want to cover off the Route Service. As with the other API’s provided by Bing this service provides the caller with the ability to :-

  • Calculate a Route – directions for walking, driving or transit routes are supported between waypoints.
  • Calculate Routes from Major Roads – driving routes using major roads to landmarks.

As you can see there are a number of supported actions the service can perform depending on your requirements. They all provide you with the ability to create a request that can be passed to the endpoint which intern calculates a route and returns a collection of points and directions. However, these API’s and what they do IMHO are not very well documented, the start here and finish there is trivial however the major roads and major routes and how to use these is not clear at times, also the objects returned from certain requests are complex. (If you are a Bing REST API person it would be great to hear from you so that we can gain a better understanding)

Obviously this has influenced the current implementation of the wrapper for getting Route information. Our objective as with Location was to simplify how you wire these components in to your application. Therefore the WP7C abstracts the different data types that are supported by the Bing Route service by wrapping all the supported types into super types that the WP7C can process.

So, from a UI prospective in terms of what you can bind to from Xaml there are 3 types that you need to know about :-

  • Landmark
  • GeoCoordinate
  • Address

As with the location service we use the CriterionFactory to help with the construction of the request. As mentioned above the Bing Route service supports 2 mechanisms; Calculate a Route; and Calculate Routes from Major Roads. The code below is taken from the Routes VM found in the Bing sample and illustrates how you can wire the calls into your app.

Calculate a Route using Landmarks

var waypoints = new List<WayPoint> 
{ 
      new WayPoint { Landmark = this.startLandmark }, 
      new WayPoint { Landmark = this.finishLandmark } 
};

this.SearchForRouteByLandmarks(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate a Route using an Address

var waypoints = new List<WayPoint>
{
      new WayPoint { Address = this.startAddress },
      new WayPoint { Address = this.finishAddress }
};

this.SearchForRouteByAddresses(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate a Route using an Points

var waypoints = new List<WayPoint>
{
      new WayPoint { Point = this.startPoint },
      new WayPoint { Point = this.finishPoint }
};

this.SearchForRouteByPoints(CriterionFactory.CreateRouteSearch(waypoints));

 

Calculate Routes from Major Roads

var routeDestination = new RouteDestination
{
      Landmark = this.majorRoads 
};

this.SearchForRouteFromMajorRoads(
      CriterionFactory.CreateRouteSearchFromMajorRoads(
            routeDestination, DistanceUnit.Kilometer));

 

The above methods wrap up the Rx calls that will do the request as I wanted to illustrate not only how simple you can make it but also that we wrap all of the above 3 concrete types into another type called WayPoint for all of the different permutations of the calls you have a consistent pattern

            CriterionFactory.CreateRouteSearch(waypoints)

Now that we have covered the supported types and the CriterionFactory we can put all this together and look at how we use Rx to make the async calls.

Setup the Request (the code below is for calcualting a route by using landmarks)

private void SearchForRouteByLandmarks(IRouteSearchCriterion criterion)
{
    DispatcherHelper.CheckBeginInvokeOnUI(
        () => { this.LandmarkStatus = "Calculating..."; });

    this.bingMapService.CalculateARoute(criterion)
        .ObserveOnDispatcher()
        .Subscribe(this.ProcessBingRouteSearchResponse,
                   FailedSearch,
                   () => 
                   { 
                     this.LandmarkStatus = 
                     "Completed, scroll left or right to see Directions &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; Maps..."; 
                   });
}

 

Handle the Response, Successful

private void ProcessBingRouteSearchResponse(RouteSearchResult result)
{
     if (result == null)
     {
          return;
     }

      this.SearchResult = result;
      if (this.SearchResult.Points.Count != 0)
      {
           this.CurrentMapSearchCenterPoint = this.SearchResult.Points[0];
           this.ItineraryItems = this.SearchResult.RouteLegs.SelectMany(leg => leg.ItineraryItems).ToList();
      }
}

Handle the Response, Fail

private static void FailedSearch(Exception exn)
{
      MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message),
                                    "Route Search",
                                    MessageBoxButton.OK);
}

 

We need to now pay some attention to the result object that comes back, which is the same for both service calls but they are processed differently. The Calculate a route response has a single object with some properties that are useful.

Distance information

<TextBlock Text="Distance Units:" />
<TextBlock Text="{Binding SearchResult.DistanceUnit}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1" />
<TextBlock Text="Duration Units:"
            Grid.Row="1" />
<TextBlock Text="{Binding SearchResult.DurationUnit}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="1" />
<TextBlock Text="Travel Distance:"
            Grid.Row="2" />
<TextBlock Text="{Binding SearchResult.TravelDistance}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="2" />
<TextBlock Text="Travel Duration:"
            Grid.Row="3" />
<TextBlock Text="{Binding SearchResult.TravelDuration}"
            Foreground="LightGreen"
            TextAlignment="Right"
            Padding="0,0,20,0"
            Grid.Column="1"
            Grid.Row="3" />

 

Directions for the route

<ListBox Grid.Row="2"
        BorderThickness="3"
        BorderBrush="White"
        Padding="5,5,5,5"
        ItemsSource="{Binding SearchResult.RouteLegs}"
        ItemTemplate="{StaticResource RouteLegsDataTemplate}"
        ScrollViewer.VerticalScrollBarVisibility="Visible" />
[sourcecode='xml']

The map

[sourcecode='xml']
<Microsoft_Phone_Controls_Maps:Map x:Name="searchresultsnearbymap"
                         ZoomLevel="{Binding ZoomLevel, Mode=TwoWay}"
                         Center="{Binding CurrentMapSearchCenterPoint, Mode=TwoWay}"
                         ZoomBarVisibility="Collapsed"
                         CopyrightVisibility="Visible"
                         AnimationLevel="UserInput"
                         HorizontalContentAlignment="Stretch"
                         VerticalContentAlignment="Stretch"
                         Grid.RowSpan="2"
                         Background="{StaticResource SemiOpaqueDarkBackBrush}">

    <!--Need to add a map pin to show what your current position is on the map-->
    <Microsoft_Phone_Controls_Maps:MapPolyline Stroke="Green"
                         Locations="{Binding SearchResult.Points}"
                         StrokeThickness="6"
                         Opacity="0.7" />

    <Microsoft_Phone_Controls_Maps:MapItemsControl x:Name="ResultsList"
                         ItemTemplate="{StaticResource MapPinDataTemplate}"
                         ItemsSource="{Binding ItineraryItems}" />
</Microsoft_Phone_Controls_Maps:Map>

 

That now completes the loop, we are done! I hope that you will agree this is far simpler, more performant and highly reuseable way of incorporating a rich geo location style experience into you apps, when compared to the wsdl implementation.

The Major Roads implementation is the same pattern however we need to call the methods specific to this request type both on the Criterion Factory and on the Bing Map Service.

The Major Roads implementation seems to be using some sort of fuzzy logic with regards to what you can request. Which is very funky.
The description on MSDN

In some cases, you may prefer generating a route from a major intersection to a target destination, rather than generating a true point to point route. For example, most major landmark websites show directions “coming from the North” or “coming from the West”.

For example, the major road service supports a request like calculate the driving route to the Space Needle in Seattle and the service will return the directions. Cool!

In summary, the steps required to use the Route Service are :-

1. Create the type of request you want to make; Landmark, Address or Point.
2. Create a list of waypoints using the type declared in step 1.
3. Use the Criterion Factory to create a Route Search based on the waypoints you pass in.
4. Call the Bing Map Service method Calculate a Route and pass in the Route Search Criterion generated by the factory
5. Handle the Search Result object returned by the Bing Map Service.
6. Data bind the Search Result properties to Xaml Map control.

In the next post we can take a look at the imagery service.

Enjoy!

Be Sociable, Share!

Tags:

One Response to “WP7Contrib – Bing Service Wrapper Part II – Route”

  1. [...] WP7Contrib – Bing Service Wrapper Part II – Route [...]


Leave a Reply