Calculating a Route Using Bing Maps SOAP Services

This documentation is no longer available on MSDN, however it is available as a CHM download.

You can use the Bing Maps SOAP Services to add additional mapping functionality to your Bing Maps Silverlight Control application. To add routing capabilities, use the Geocode Service to geocode user location inputs and then use the Route Service to calculate a route. The Route Service returns points that define the route. These route points can be rendered on your map using the Bing Maps Silverlight Control.

To incorporate Bing Maps SOAP Services functionality into your Silverlight application, you need to take the following steps:

  • Create a Silverlight project in Visual Studio 2008 or Visual Studio 2010 that displays a map. Add two text box controls and a button.

  • Add service references to the Bing Maps SOAP Services that you want to use. In this topic, you need to use the Bing Maps Geocode Service and the Bing Maps Route Service.

  • Add code to make geocoding and routing requests. Bing Maps SOAP Services requires that your Bing Maps Key be set in the request.

  • Use the returned results of the Bing Maps SOAP Services requests to render a route on the Silverlight map.

Note

In order to reduce the complexity of the code in this topic, error handling was removed. After you have implemented your application as described below, you should add code to verify input values.

Create a Silverlight Project

Start by creating a Silverlight project in Visual Studio.

  1. Open Visual Studio.

  2. Select File from the main menu.

  3. Select New, and then Project from the menu.

  4. In the New Project dialog box, under the language of your choice (for example, Visual C# or Visual Basic), select Silverlight.

  5. Select a Silverlight Application from the available templates and then click OK.

  6. When asked, be sure the Host the Silverlight in a new Web site option is checked and the ASP .NET Web Application Project type is selected.

    Note

    Because of URL access restrictions in Silverlight, your Web page must be hosted using the HTTP scheme for it to access Bing Maps map tiles. For more information about Silverlight URL access restrictions, see https://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx.

  7. Next, reference the map control in your project and display the default map in your application. With the Silverlight project selected (not the Web project), select Project then Add Reference from the Visual Studio main menu. In the Add Reference dialog box, click the Browse tab.

  8. Browse to the location of your Bing Maps Silverlight Control installation. Open the Libraries folder, select the Microsoft.Maps.MapControl.dll and Microsoft.Maps.MapControl.Common.dll files and click OK.

  9. Once the map control assemblies are referenced, you can add the map element <m:Map/> to your page. Add a Name property to the map element so that you can reference it in your Visual C# or Visual Basic code as well as a CredentialsProvider property to authenticate requests. Your final MainPage.xaml should look like this:

    <UserControl x:Class="SilverlightApplication1.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl">
        <Grid x:Name="LayoutRoot" Background="White">
            <m:Map Name="myMap" CredentialsProvider="Your Key"/>
        </Grid>
    </UserControl>
    

Add Controls for User Input

Next, you need to add two TextBox controls to input the start and end locations, and a that executes the route calculation. This topic uses a Grid to organize the map and controls on the Web page, but there are other ways to do this. Detailed information about laying out and designing your Silverlight Web page is found in the Silverlight Layout System topic.

  1. First add a basic <Grid></Grid> to the MainPage.xaml. You can either type this directly into the XAML code window, or you can open the Toolbox under the View menu in Visual Studio to drag and drop controls into the XAML code window.

  2. The default Grid control has a dimension of 1x1, so use <Grid.RowDefinitions> to define extra rows (and columns) in the Grid as well as how to size the Grid rows. In this example, the map fills the first row of the base Grid and the second row contains another Grid, which will contain the controls. Use the Grid.Row property to identify which row each element should be placed. Your code should look like this:

    <UserControl x:Class="SilverlightApplication1.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl">
        <Grid x:Name="LayoutRoot" Background="White">
             <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="auto"/>
             </Grid.RowDefinitions>
             <m:Map Name="myMap" CredentialsProvider="Your Key" Grid.Row="0"></m:Map>
             <Grid Grid.Row="1"></Grid>
        </Grid>
    </UserControl>
    
  3. Finally, add two text boxes and a button to the Grid in the second row of the base Grid. Add some text, coloring, Grid.Row properties to identify the order of the controls on your Web page, and be sure to add a Name property to each element so that you can reference the element in your code. After you have done this, your MainPage.xaml should look like:

    <UserControl x:Class="SilverlightApplication1.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl">
        <Grid x:Name="LayoutRoot" Background="White">
             <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="auto"/>
             </Grid.RowDefinitions>
             <m:Map Name="myMap" CredentialsProvider="Your Key" Grid.Row="0"></m:Map>
             <Grid Grid.Row="1">
                <Grid.RowDefinitions>
                   <RowDefinition></RowDefinition>
                   <RowDefinition></RowDefinition>
                   <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <TextBox Name="txtStart" Grid.Row="0" Text="Enter the start address or location here." Background="LightGray"    Width="300" HorizontalAlignment="Left"></TextBox>
                <TextBox Name="txtEnd" Grid.Row="1" Text="Enter the end address or location here." Background="LightGray"  Width="300" HorizontalAlignment="Left"></TextBox>
                <Button Name="btnCalculateRoute" Grid.Row="2" Content="Calculate Route" Background="Black"  Width="100" HorizontalAlignment="Left"></Button>
            </Grid>
        </Grid>
    </UserControl>
    

Add the Bing Maps Web Service References

The next step is to add Bing Maps SOAP Services references to the Silverlight application so that you can use their functionality in your code.

  1. First, add a service reference to the Bing Maps Geocode Service. In the Solution Explorer in Visual Studio, right click on the SilverlightApplication1 project and select Add Service Reference. Make sure you are adding the service references to the Silverlight project and not the Web project.

  2. Enter https://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc into the Address field and click Go.

  3. Type GeocodeService into the Namespace field and click OK.

  4. Repeat steps 1-3 using https://dev.virtualearth.net/webservices/v1/routeservice/routeservice.svc as the Address and RouteService as the Namespace.

Geocode the user input values

The next step is to make requests to the Bing Maps Geocode Service to retrieve the coordinates of the user location inputs. These coordinates are then passed to the Bing Maps Route Service to calculate a route. Silverlight uses an asynchronous model, so requests to the Bing Maps SOAP Services also need to be asynchronous. This means you need to make the initial request and define a callback function for when the request is returned. In addition, you need a way to track your geocode requests so that you know which result is returned when the callback function is called.

  1. A Bing Maps SOAP Services geocode request accepts a query string which can contain an address or a location. The Bing Maps Geocode Service parses this query string and then matches the address or location to a point on the map. Because the Bing Maps Geocode Service is called more than once, the asynchronous geocode request should include a user state, which identifies the request and can be used to identify the response. Paste the code below within the namespace of MainPage.xaml.cs or MainPage.xaml.vb.

    // This method accepts a geocode query string as well as a ‘waypoint index’, which will be used to track each asynchronous geocode request.
    private void Geocode(string strAddress, int waypointIndex)
            {
                // Create the service variable and set the callback method using the GeocodeCompleted property.
                GeocodeService.GeocodeServiceClient geocodeService = new GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
                geocodeService.GeocodeCompleted += new EventHandler<GeocodeService.GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);
    
                // Set the credentials and the geocode query, which could be an address or location.
                GeocodeService.GeocodeRequest geocodeRequest = new GeocodeService.GeocodeRequest();
                geocodeRequest.Credentials = new Credentials();
                geocodeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.CredentialsProvider).ApplicationId; 
                geocodeRequest.Query = strAddress;
    
                // Make the asynchronous Geocode request, using the ‘waypoint index’ as 
                //   the user state to track this request and allow it to be identified when the response is returned.
                geocodeService.GeocodeAsync(geocodeRequest, waypointIndex);
            }
    
        ' This method accepts a geocode query string as well as a ‘waypoint index’, which will be used to track each asynchronous geocode request.
        Private Sub Geocode(ByVal strAddress As String, ByVal waypointIndex As Integer)
            ' Create the service variable and set the callback method using the GeocodeCompleted property.
            Dim geocodeServiceRequestor As New GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService")
            AddHandler geocodeServiceRequestor.GeocodeCompleted, AddressOf geocodeService_GeocodeCompleted
    
            ' Set the credentials and the geocode query, which could be an address or location.
            Dim geocodeRequest As New GeocodeService.GeocodeRequest()
            geocodeRequest.Credentials = New Credentials()
            geocodeRequest.Credentials.ApplicationId = (CType(myMap.CredentialsProvider, ApplicationIdCredentialsProvider)).ApplicationId
            geocodeRequest.Query = strAddress
    
            ' Make the asynchronous Geocode request, using the ‘waypoint index’ as 
            '   the user state to track this request and allow it to be identified when the response is returned.
            geocodeServiceRequestor.GeocodeAsync(geocodeRequest, waypointIndex)
        End Sub
    

    Tip

    For ease of use, the shared Bing Maps types work together seamlessly. For example, notice in the code above that the GeocodeRequest.Credentials property of the Bing Maps SOAP Services can be instantiated as a Credentials type of the Bing Maps Silverlight Control.

  2. When the Bing Maps SOAP Services geocode request gets returned, the method specified in the GeocodeCompleted property of the service client variable is called. In this callback method, retrieve the results and store them in a global variable called geocodeResults so that they can be used to calculate a route when the results have all been returned.

    // This is the global internal variable where results are stored. These are accessed later to calculate the route.
    internal GeocodeService.GeocodeResult[] geocodeResults;
    
    // This is the Geocode request callback method.
    private void geocodeService_GeocodeCompleted(object sender, GeocodeService.GeocodeCompletedEventArgs e)
            {
                // Retrieve the user state of this response (the ‘waypoint index’) to identify which geocode request 
                //   it corresponds to.
                int waypointIndex = System.Convert.ToInt32(e.UserState);
    
                // Retrieve the GeocodeResult for this response and store it in the global variable geocodeResults, using
                //   the waypoint index to position it in the array.
                geocodeResults[waypointIndex] = e.Result.Results[0];
    
                // Look at each element in the global gecodeResults array to figure out if more geocode responses still 
                //   need to be returned.
    
                bool doneGeocoding = true;
    
                foreach (GeocodeService.GeocodeResult gr in geocodeResults)
                {
                    if (gr == null)
                    {
                        doneGeocoding = false;
                    }
                }
    
                // If the geocodeResults array is totally filled, then calculate the route.
                if (doneGeocoding)
                    CalculateRoute(geocodeResults);
    
            }
    
        ' This is the global internal variable where results are stored. These are accessed later to calculate the route.
        Friend geocodeResults() As GeocodeService.GeocodeResult
    
        ' This is the Geocode request callback method.
        Private Sub geocodeService_GeocodeCompleted(ByVal sender As Object, ByVal e As GeocodeService.GeocodeCompletedEventArgs)
            ' Retrieve the user state of this response (the ‘waypoint index’) to identify which geocode request 
            '   it corresponds to.
            Dim waypointIndex As Integer = System.Convert.ToInt32(e.UserState)
    
            ' Retrieve the GeocodeResult for this response and store it in the global variable geocodeResults, using
            '   the waypoint index to position it in the array.
            geocodeResults(waypointIndex) = e.Result.Results(0)
    
            ' Look at each element in the global gecodeResults array to figure out if more geocode responses still 
            '   need to be returned.
    
            Dim doneGeocoding As Boolean = True
    
            For Each gr As GeocodeService.GeocodeResult In geocodeResults
                If gr Is Nothing Then
                    doneGeocoding = False
                End If
            Next gr
    
            ' If the geocodeResults array is totally filled, then calculate the route.
            If doneGeocoding Then
                CalculateRoute(geocodeResults)
            End If
    
        End Sub
    
  3. Now that you have created a method to geocode a given address or location string, you need to provide a way to execute this method. In the MainPage.xaml, add the Click property to the Button element and select <New Event Handler> when Intellisense prompts with this value. This gives the click event handler method the default name of btnCalculateRoute_Click. The MainPage.xaml should look like:

    <UserControl x:Class="SilverlightApplication1.MainPage"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl">
        <Grid x:Name="LayoutRoot" Background="White">
             <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="auto"/>
             </Grid.RowDefinitions>
             <m:Map Name="myMap" CredentialsProvider="Your Key" Grid.Row="0"></m:Map>
             <Grid Grid.Row="1">
                <Grid.RowDefinitions>
                   <RowDefinition></RowDefinition>
                   <RowDefinition></RowDefinition>
                   <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <TextBox Name="txtStart" Grid.Row="0" Text="Enter the start address or location here." Background="LightGray"    Width="300" HorizontalAlignment="Left"></TextBox>
                <TextBox Name="txtEnd" Grid.Row="1" Text="Enter the end address or location here." Background="LightGray"  Width="300" HorizontalAlignment="Left"></TextBox>
                <Button Name="btnCalculateRoute" Grid.Row="2" Content="Calculate Route" Background="Black"  Width="100" HorizontalAlignment="Left" Click="btnCalculateRoute_Click"></Button>
            </Grid>
        </Grid>
    </UserControl>
    
  4. Go back to the MainPage.xaml.cs or MainPage.xaml.vb file and notice that Visual Studio has automatically inserted the btnCalculateRoute_Click method. Inside this method, call the Geocode method that you created to geocode the input value of the text boxes. This is also a fine place to initialize the geocodeResults array. The btnCalculateRoute_Click should look like:

    private void btnCalculateRoute_Click(object sender, RoutedEventArgs e)
       {
          // Initialize the length of the results array. In this sample we have two waypoints.
          geocodeResults = new GeocodeService.GeocodeResult[2];
    
          // Make the two Geocode requests using the values of the text boxes. Also pass the waypoint indexes 
          //   of these two values within the route.
          Geocode(txtStart.Text, 0);
          Geocode(txtEnd.Text, 1);
       }
    
    Private Sub btnCalculateRoute_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
      ' Initialize the length of the results array. In this sample we have two waypoints.
      geocodeResults = New GeocodeService.GeocodeResult(1){}
    
      ' Make the two Geocode requests using the values of the text boxes. Also pass the waypoint indexes 
      '   of these two values within the route.
      Geocode(txtStart.Text, 0)
      Geocode(txtEnd.Text, 1)
    End Sub
    

Add code to calculate and display a route

Finally we need to implement the route calculation request.

  1. As with the geocode request, the calculate route request is asynchronous so you need to specify the callback function. A CalculateRoute request contains the route waypoints as well as any options. In this example the route points that define the shape of the route on the map need to be returned as well, so set the RoutePathType to Points. The CalculateRoute method called by the geocodeService_GeocodeCompleted method is as follows:

    // This method makes the initial CalculateRoute asynchronous request using the results of the Geocode Service.
    private void CalculateRoute(GeocodeService.GeocodeResult[] results)
            {
                // Create the service variable and set the callback method using the CalculateRouteCompleted property.
                RouteService.RouteServiceClient routeService = new RouteService.RouteServiceClient("BasicHttpBinding_IRouteService");
                routeService.CalculateRouteCompleted += new EventHandler<RouteService.CalculateRouteCompletedEventArgs>(routeService_CalculateRouteCompleted);
    
                // Set the token.
                RouteService.RouteRequest routeRequest = new RouteService.RouteRequest();
                routeRequest.Credentials = new Credentials();
                routeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.CredentialsProvider).ApplicationId; 
    
                // Return the route points so the route can be drawn.
                routeRequest.Options = new RouteService.RouteOptions();
                routeRequest.Options.RoutePathType = RouteService.RoutePathType.Points;
    
                // Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
                routeRequest.Waypoints = new System.Collections.ObjectModel.ObservableCollection<RouteService.Waypoint>();
                foreach (GeocodeService.GeocodeResult result in results)
                {
                    routeRequest.Waypoints.Add(GeocodeResultToWaypoint(result));
                }
    
                // Make the CalculateRoute asnychronous request.
                routeService.CalculateRouteAsync(routeRequest);
            }
    
        ' This method makes the initial CalculateRoute asynchronous request using the results of the Geocode Service.
        Private Sub CalculateRoute(ByVal results() As GeocodeService.GeocodeResult)
            ' Create the service variable and set the callback method using the CalculateRouteCompleted property.
            Dim routeServiceRequestor As New RouteService.RouteServiceClient("BasicHttpBinding_IRouteService")
            AddHandler routeServiceRequestor.CalculateRouteCompleted, AddressOf routeService_CalculateRouteCompleted
    
            ' Set the token.
            Dim routeRequest As New RouteService.RouteRequest()
            routeRequest.Credentials = New Credentials()
            routeRequest.Credentials.ApplicationId = (CType(myMap.CredentialsProvider, ApplicationIdCredentialsProvider)).ApplicationId
    
            ' Return the route points so the route can be drawn.
            routeRequest.Options = New RouteService.RouteOptions()
            routeRequest.Options.RoutePathType = routeService.RoutePathType.Points
    
            ' Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
            routeRequest.Waypoints = New System.Collections.ObjectModel.ObservableCollection(Of RouteService.Waypoint)()
            For Each result As GeocodeService.GeocodeResult In results
                routeRequest.Waypoints.Add(GeocodeResultToWaypoint(result))
            Next result
    
            ' Make the CalculateRoute asnychronous request.
            routeServiceRequestor.CalculateRouteAsync(routeRequest)
        End Sub
    

    The CalculateRoute method above uses a helper method called GeocodeResultToWaypoint, which pulls the latitude and longitude values from the geocode result and assigns it to the latitude and longitude property of a waypoint.

            private RouteService.Waypoint GeocodeResultToWaypoint(GeocodeService.GeocodeResult result)
            {
                RouteService.Waypoint waypoint = new RouteService.Waypoint();
                waypoint.Description = result.DisplayName;
                waypoint.Location = new Location();
                waypoint.Location.Latitude = result.Locations[0].Latitude;
                waypoint.Location.Longitude = result.Locations[0].Longitude;
                return waypoint;
            }
    
        Private Function GeocodeResultToWaypoint(ByVal result As GeocodeService.GeocodeResult) As RouteService.Waypoint
            Dim waypoint As New RouteService.Waypoint()
            waypoint.Description = result.DisplayName
            waypoint.Location = New Location()
            waypoint.Location.Latitude = result.Locations(0).Latitude
            waypoint.Location.Longitude = result.Locations(0).Longitude
            Return waypoint
        End Function
    

    Tip

    For ease of use, the shared Bing Maps types work together seamlessly. For example, notice in the code above that theWaypoint.Location property of the Bing Maps SOAP Services can be instantiated as a Location type of the Bing Maps Silverlight Control.

  2. Next, create the routeService_CalculateRouteCompleted callback method which renders the route on the map. Create a map layer in which to draw the route.

            // This is the callback method for the CalculateRoute request.
            private void routeService_CalculateRouteCompleted(object sender, RouteService.CalculateRouteCompletedEventArgs e)
            {
    
                // If the route calculate was a success and contains a route, then draw the route on the map.
                if ((e.Result.ResponseSummary.StatusCode == RouteService.ResponseStatusCode.Success) & (e.Result.Result.Legs.Count != 0))
                {
                    // Set properties of the route line you want to draw.
                    Color routeColor = Colors.Blue;
                    SolidColorBrush routeBrush = new SolidColorBrush(routeColor);
                    MapPolyline routeLine = new MapPolyline();
                    routeLine.Locations = new LocationCollection();
                    routeLine.Stroke = routeBrush;
                    routeLine.Opacity = 0.65;
                    routeLine.StrokeThickness = 5.0;
    
                    // Retrieve the route points that define the shape of the route.
                    foreach (Location p in e.Result.Result.RoutePath.Points)
                    {
                        routeLine.Locations.Add(new Location(p.Latitude, p.Longitude));
                    }
    
                    // Add a map layer in which to draw the route.
                    MapLayer myRouteLayer = new MapLayer();
                    myMap.Children.Add(myRouteLayer);
    
                    // Add the route line to the new layer.
                    myRouteLayer.Children.Add(routeLine);
    
                    // Figure the rectangle which encompasses the route. This is used later to set the map view.
                    LocationRect rect = new LocationRect(routeLine.Locations[0], routeLine.Locations[routeLine.Locations.Count - 1]);
    
                    // For each geocode result (which are the waypoints of the route), draw a dot on the map.
                    foreach (GeocodeService.GeocodeResult gr in geocodeResults)
                    {
                        Ellipse point = new Ellipse();
                        point.Width = 10;
                        point.Height = 10;
                        point.Fill = new SolidColorBrush(Colors.Red);
                        point.Opacity = 0.65;
                        Location location = new Location(gr.Locations[0].Latitude, gr.Locations[0].Longitude);
                        MapLayer.SetPosition(point, location);
                        MapLayer.SetPositionOrigin(point, PositionOrigin.Center);
    
                        // Add the drawn point to the route layer.                    
                        myRouteLayer.Children.Add(point);
                    }
    
                    // Set the map view using the rectangle which bounds the rendered route.
                    myMap.SetView(rect);
                }
          }
    
    ' This is the callback method for the CalculateRoute request.
    Private Sub routeService_CalculateRouteCompleted(ByVal sender As Object, ByVal e As RouteService.CalculateRouteCompletedEventArgs)
    
    ' If the route calculate was a success and contains a route, then draw the route on the map.
    If (e.Result.ResponseSummary.StatusCode = RouteService.ResponseStatusCode.Success) And (e.Result.Result.Legs.Count <> 0) Then
    ' Set properties of the route line you want to draw.
    Dim routeColor As Color = Colors.Blue
    Dim routeBrush As New SolidColorBrush(routeColor)
    Dim routeLine As New MapPolyline()
    routeLine.Locations = New LocationCollection()
    routeLine.Stroke = routeBrush
    routeLine.Opacity = 0.65
    routeLine.StrokeThickness = 5.0
    
    ' Retrieve the route points that define the shape of the route.
    For Each p As Location In e.Result.Result.RoutePath.Points
    routeLine.Locations.Add(New Location(p.Latitude, p.Longitude))
    Next p
    
    ' Add a map layer in which to draw the route.
    Dim myRouteLayer As New MapLayer()
    myMap.Children.Add(myRouteLayer)
    
    ' Add the route line to the new layer.
    myRouteLayer.Children.Add(routeLine)
    
    ' Figure the rectangle which encompasses the route. This is used later to set the map view.
    Dim rect As New LocationRect(routeLine.Locations(0), routeLine.Locations(routeLine.Locations.Count - 1))
    
    ' For each geocode result (which are the waypoints of the route), draw a dot on the map.
    For Each gr As GeocodeService.GeocodeResult In geocodeResults
    Dim point As New Ellipse()
    point.Width = 10
    point.Height = 10
    point.Fill = New SolidColorBrush(Colors.Red)
    point.Opacity = 0.65
    Dim location_Renamed As New Location(gr.Locations(0).Latitude, gr.Locations(0).Longitude)
    MapLayer.SetPosition(point, location_Renamed)
    MapLayer.SetPositionOrigin(point, PositionOrigin.Center)
    
    ' Add the drawn point to the route layer.                    
    myRouteLayer.Children.Add(point)
    Next gr
    
    ' Set the map view using the rectangle which bounds the rendered route.
    myMap.SetView(rect)
    End If
    End Sub
    
  3. The final MainPage.xaml.cs and MainPage.xaml.vb code is below.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Shapes;
    
    using Microsoft.Maps.MapControl;
    
    namespace SilverlightApplication1
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
            }
    
            // This method accepts a geocode query string as well as a ‘waypoint index’, which will be used to track each asynchronous geocode request.
            private void Geocode(string strAddress, int waypointIndex)
            {
                // Create the service variable and set the callback method using the GeocodeCompleted property.
                GeocodeService.GeocodeServiceClient geocodeService = new GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
                geocodeService.GeocodeCompleted += new EventHandler<GeocodeService.GeocodeCompletedEventArgs>(geocodeService_GeocodeCompleted);
    
                // Set the credentials and the geocode query, which could be an address or location.
                GeocodeService.GeocodeRequest geocodeRequest = new GeocodeService.GeocodeRequest();
                geocodeRequest.Credentials = new Credentials();
                geocodeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.CredentialsProvider).ApplicationId;
                geocodeRequest.Query = strAddress;
    
                // Make the asynchronous Geocode request, using the ‘waypoint index’ as 
                //   the user state to track this request and allow it to be identified when the response is returned.
                geocodeService.GeocodeAsync(geocodeRequest, waypointIndex);
            }
    
            // This is the global internal variable where results are stored. These are accessed later to calculate the route.
            internal GeocodeService.GeocodeResult[] geocodeResults;
    
            // This is the Geocode request callback method.
            private void geocodeService_GeocodeCompleted(object sender, GeocodeService.GeocodeCompletedEventArgs e)
            {
                // Retrieve the user state of this response (the ‘waypoint index’) to identify which geocode request 
                //   it corresponds to.
                int waypointIndex = System.Convert.ToInt32(e.UserState);
    
                // Retrieve the GeocodeResult for this response and store it in the global variable geocodeResults, using
                //   the waypoint index to position it in the array.
                geocodeResults[waypointIndex] = e.Result.Results[0];
    
                // Look at each element in the global gecodeResults array to figure out if more geocode responses still 
                //   need to be returned.
    
                bool doneGeocoding = true;
    
                foreach (GeocodeService.GeocodeResult gr in geocodeResults)
                {
                    if (gr == null)
                    {
                        doneGeocoding = false;
                    }
                }
    
                // If the geocodeResults array is totally filled, then calculate the route.
                if (doneGeocoding)
                    CalculateRoute(geocodeResults);
    
            }
    
            private void btnCalculateRoute_Click(object sender, RoutedEventArgs e)
            {
                // Initialize the length of the results array. In this sample we have two waypoints.
                geocodeResults = new GeocodeService.GeocodeResult[2];
    
                // Make the two Geocode requests using the values of the text boxes. Also pass the waypoint indexes 
                //   of these two values within the route.
                Geocode(txtStart.Text, 0);
                Geocode(txtEnd.Text, 1);
            }
    
            // This method makes the initial CalculateRoute asynchronous request using the results of the Geocode Service.
            private void CalculateRoute(GeocodeService.GeocodeResult[] results)
            {
                // Create the service variable and set the callback method using the CalculateRouteCompleted property.
                RouteService.RouteServiceClient routeService = new RouteService.RouteServiceClient("BasicHttpBinding_IRouteService");
                routeService.CalculateRouteCompleted += new EventHandler<RouteService.CalculateRouteCompletedEventArgs>(routeService_CalculateRouteCompleted);
    
                // Set the credentials.
                RouteService.RouteRequest routeRequest = new RouteService.RouteRequest();
                routeRequest.Credentials = new Credentials();
                routeRequest.Credentials.ApplicationId = ((ApplicationIdCredentialsProvider)myMap.CredentialsProvider).ApplicationId;
    
                // Return the route points so the route can be drawn.
                routeRequest.Options = new RouteService.RouteOptions();
                routeRequest.Options.RoutePathType = RouteService.RoutePathType.Points;
    
                // Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
                routeRequest.Waypoints = new System.Collections.ObjectModel.ObservableCollection<RouteService.Waypoint>();
                foreach (GeocodeService.GeocodeResult result in results)
                {
                    routeRequest.Waypoints.Add(GeocodeResultToWaypoint(result));
                }
    
                // Make the CalculateRoute asnychronous request.
                routeService.CalculateRouteAsync(routeRequest);
            }
    
            private RouteService.Waypoint GeocodeResultToWaypoint(GeocodeService.GeocodeResult result)
            {
                RouteService.Waypoint waypoint = new RouteService.Waypoint();
                waypoint.Description = result.DisplayName;
                waypoint.Location = new Location();
                waypoint.Location.Latitude = result.Locations[0].Latitude;
                waypoint.Location.Longitude = result.Locations[0].Longitude;
                return waypoint;
            }
    
            // This is the callback method for the CalculateRoute request.
            private void routeService_CalculateRouteCompleted(object sender, RouteService.CalculateRouteCompletedEventArgs e)
            {
    
                // If the route calculate was a success and contains a route, then draw the route on the map.
                if ((e.Result.ResponseSummary.StatusCode == RouteService.ResponseStatusCode.Success) & (e.Result.Result.Legs.Count != 0))
                {
                    // Set properties of the route line you want to draw.
                    Color routeColor = Colors.Blue;
                    SolidColorBrush routeBrush = new SolidColorBrush(routeColor);
                    MapPolyline routeLine = new MapPolyline();
                    routeLine.Locations = new LocationCollection();
                    routeLine.Stroke = routeBrush;
                    routeLine.Opacity = 0.65;
                    routeLine.StrokeThickness = 5.0;
    
                    // Retrieve the route points that define the shape of the route.
                    foreach (Location p in e.Result.Result.RoutePath.Points)
                    {
                        routeLine.Locations.Add(new Location(p.Latitude, p.Longitude));
                    }
    
                    // Add a map layer in which to draw the route.
                    MapLayer myRouteLayer = new MapLayer();
                    myMap.Children.Add(myRouteLayer);
    
                    // Add the route line to the new layer.
                    myRouteLayer.Children.Add(routeLine);
    
                    // Figure the rectangle which encompasses the route. This is used later to set the map view.
                    LocationRect rect = new LocationRect(routeLine.Locations[0], routeLine.Locations[routeLine.Locations.Count - 1]);
    
                    // For each geocode result (which are the waypoints of the route), draw a dot on the map.
                    foreach (GeocodeService.GeocodeResult gr in geocodeResults)
                    {
                        Ellipse point = new Ellipse();
                        point.Width = 10;
                        point.Height = 10;
                        point.Fill = new SolidColorBrush(Colors.Red);
                        point.Opacity = 0.65;
                        Location location = new Location(gr.Locations[0].Latitude, gr.Locations[0].Longitude);
                        MapLayer.SetPosition(point, location);
                        MapLayer.SetPositionOrigin(point, PositionOrigin.Center);
    
                        // Add the drawn point to the route layer.                    
                        myRouteLayer.Children.Add(point);
                    }
    
                    // Set the map view using the rectangle which bounds the rendered route.
                    myMap.SetView(rect);
                }
            }
        }
    }
    
    
    
    Imports Microsoft.Maps.MapControl
    
    
    Partial Public Class MainPage
        Inherits UserControl
        Public Sub New()
            InitializeComponent()
    
        End Sub
    
        ' This method accepts a geocode query string as well as a ‘waypoint index’, which will be used to track each asynchronous geocode request.
        Private Sub Geocode(ByVal strAddress As String, ByVal waypointIndex As Integer)
            ' Create the service variable and set the callback method using the GeocodeCompleted property.
            Dim geocodeServiceRequestor As New GeocodeService.GeocodeServiceClient("BasicHttpBinding_IGeocodeService")
            AddHandler geocodeServiceRequestor.GeocodeCompleted, AddressOf geocodeService_GeocodeCompleted
    
            ' Set the credentials and the geocode query, which could be an address or location.
            Dim geocodeRequest As New GeocodeService.GeocodeRequest()
            geocodeRequest.Credentials = New Credentials()
            geocodeRequest.Credentials.ApplicationId = (CType(myMap.CredentialsProvider, ApplicationIdCredentialsProvider)).ApplicationId
            geocodeRequest.Query = strAddress
    
            ' Make the asynchronous Geocode request, using the ‘waypoint index’ as 
            '   the user state to track this request and allow it to be identified when the response is returned.
            geocodeServiceRequestor.GeocodeAsync(geocodeRequest, waypointIndex)
        End Sub
    
        ' This is the global internal variable where results are stored. These are accessed later to calculate the route.
        Friend geocodeResults() As GeocodeService.GeocodeResult
    
        ' This is the Geocode request callback method.
        Private Sub geocodeService_GeocodeCompleted(ByVal sender As Object, ByVal e As GeocodeService.GeocodeCompletedEventArgs)
            ' Retrieve the user state of this response (the ‘waypoint index’) to identify which geocode request 
            '   it corresponds to.
            Dim waypointIndex As Integer = System.Convert.ToInt32(e.UserState)
    
            ' Retrieve the GeocodeResult for this response and store it in the global variable geocodeResults, using
            '   the waypoint index to position it in the array.
            geocodeResults(waypointIndex) = e.Result.Results(0)
    
            ' Look at each element in the global gecodeResults array to figure out if more geocode responses still 
            '   need to be returned.
    
            Dim doneGeocoding As Boolean = True
    
            For Each gr As GeocodeService.GeocodeResult In geocodeResults
                If gr Is Nothing Then
                    doneGeocoding = False
                End If
            Next gr
    
            ' If the geocodeResults array is totally filled, then calculate the route.
            If doneGeocoding Then
                CalculateRoute(geocodeResults)
            End If
    
        End Sub
    
        Private Sub btnCalculateRoute_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Initialize the length of the results array. In this sample we have two waypoints.
            geocodeResults = New GeocodeService.GeocodeResult(1) {}
    
            ' Make the two Geocode requests using the values of the text boxes. Also pass the waypoint indexes 
            '   of these two values within the route.
            Geocode(txtStart.Text, 0)
            Geocode(txtEnd.Text, 1)
        End Sub
    
        ' This method makes the initial CalculateRoute asynchronous request using the results of the Geocode Service.
        Private Sub CalculateRoute(ByVal results() As GeocodeService.GeocodeResult)
            ' Create the service variable and set the callback method using the CalculateRouteCompleted property.
            Dim routeServiceRequestor As New RouteService.RouteServiceClient("BasicHttpBinding_IRouteService")
            AddHandler routeServiceRequestor.CalculateRouteCompleted, AddressOf routeService_CalculateRouteCompleted
    
            ' Set the token.
            Dim routeRequest As New RouteService.RouteRequest()
            routeRequest.Credentials = New Credentials()
            routeRequest.Credentials.ApplicationId = (CType(myMap.CredentialsProvider, ApplicationIdCredentialsProvider)).ApplicationId
    
            ' Return the route points so the route can be drawn.
            routeRequest.Options = New RouteService.RouteOptions()
            routeRequest.Options.RoutePathType = routeService.RoutePathType.Points
    
            ' Set the waypoints of the route to be calculated using the Geocode Service results stored in the geocodeResults variable.
            routeRequest.Waypoints = New System.Collections.ObjectModel.ObservableCollection(Of RouteService.Waypoint)()
            For Each result As GeocodeService.GeocodeResult In results
                routeRequest.Waypoints.Add(GeocodeResultToWaypoint(result))
            Next result
    
            ' Make the CalculateRoute asnychronous request.
            routeServiceRequestor.CalculateRouteAsync(routeRequest)
        End Sub
    
        Private Function GeocodeResultToWaypoint(ByVal result As GeocodeService.GeocodeResult) As RouteService.Waypoint
            Dim waypoint As New RouteService.Waypoint()
            waypoint.Description = result.DisplayName
            waypoint.Location = New Location()
            waypoint.Location.Latitude = result.Locations(0).Latitude
            waypoint.Location.Longitude = result.Locations(0).Longitude
            Return waypoint
        End Function
    
        ' This is the callback method for the CalculateRoute request.
        Private Sub routeService_CalculateRouteCompleted(ByVal sender As Object, ByVal e As RouteService.CalculateRouteCompletedEventArgs)
    
            ' If the route calculate was a success and contains a route, then draw the route on the map.
            If (e.Result.ResponseSummary.StatusCode = RouteService.ResponseStatusCode.Success) And (e.Result.Result.Legs.Count <> 0) Then
                ' Set properties of the route line you want to draw.
                Dim routeColor As Color = Colors.Blue
                Dim routeBrush As New SolidColorBrush(routeColor)
                Dim routeLine As New MapPolyline()
                routeLine.Locations = New LocationCollection()
                routeLine.Stroke = routeBrush
                routeLine.Opacity = 0.65
                routeLine.StrokeThickness = 5.0
    
                ' Retrieve the route points that define the shape of the route.
                For Each p As Location In e.Result.Result.RoutePath.Points
                    routeLine.Locations.Add(New Location(p.Latitude, p.Longitude))
                Next p
    
                ' Add a map layer in which to draw the route.
                Dim myRouteLayer As New MapLayer()
                myMap.Children.Add(myRouteLayer)
    
                ' Add the route line to the new layer.
                myRouteLayer.Children.Add(routeLine)
    
                ' Figure the rectangle which encompasses the route. This is used later to set the map view.
                Dim rect As New LocationRect(routeLine.Locations(0), routeLine.Locations(routeLine.Locations.Count - 1))
    
                ' For each geocode result (which are the waypoints of the route), draw a dot on the map.
                For Each gr As GeocodeService.GeocodeResult In geocodeResults
                    Dim point As New Ellipse()
                    point.Width = 10
                    point.Height = 10
                    point.Fill = New SolidColorBrush(Colors.Red)
                    point.Opacity = 0.65
                    Dim location_Renamed As New Location(gr.Locations(0).Latitude, gr.Locations(0).Longitude)
                    MapLayer.SetPosition(point, location_Renamed)
                    MapLayer.SetPositionOrigin(point, PositionOrigin.Center)
    
                    ' Add the drawn point to the route layer.                    
                    myRouteLayer.Children.Add(point)
                Next gr
    
                ' Set the map view using the rectangle which bounds the rendered route.
                myMap.SetView(rect)
            End If
        End Sub
    End Class
    
    
    
  4. Finally, run the project, enter two locations and click the Calculate Route button. A blue route with red start and end points is drawn on the map.

    A route from Seattle to Redmond