How to: Implement a Route Calculator Using GIS Providers

  • 5 minutes to read

This example demonstrates how to create a calculating routes application using GIS services.

Follow the steps below.

  • Add an ImageTilesLayer object to the MapControl.Layers collection and assign an instance of the BingMapDataProvider class to the ImageLayer.DataProvider property. Specify the valid Bing key using the BingMapDataProvider.BingKey property.
  • Add a VectorLayer object to the MapControl.Layers collection and assign a MapItemStorage object to the VectorLayer.Data property.
  • Add an InformationLayer object to the MapControl.Layers collection and assign an instance of the BingSearchDataProvider to the InformationLayer.DataProvider property. Create a handler of the BingSearchDataProvider.SearchCompleted event. Specify the valid Bing key using the BingMapDataProviderBase.BingKey property.
  • Add an InformationLayer object to the MapControl.Layers collection and assign an instance of the BingGeocodeDataProvider to the InformationLayer.DataProvider property. Create a handler of the BingGeocodeDataProvider.LocationInformationReceived event. Specify the valid Bing key using the BingMapDataProviderBase.BingKey property.
  • Add an InformationLayer object to the MapControl.Layers collection and assign an instance of the BingRouteDataProvider to the InformationLayer.DataProvider property. Create a handler of the BingRouteDataProvider.RouteCalculated event. Specify the valid Bing key using the BingMapDataProviderBase.BingKey property.
  • For each information layer data provider set the InformationDataProviderBase.GenerateLayerItems property value to False.

    The following XAML demonstrates this in code.

    <dxm:MapControl>
        <dxm:ImageTilesLayer>
            <dxm:ImageTilesLayer.DataProvider>
                <dxm:BingMapDataProvider BingKey="{Binding Source={StaticResource bingKey}}"/>
            </dxm:ImageTilesLayer.DataProvider>
        </dxm:ImageTilesLayer>
        <dxm:VectorLayer EnableSelection="False" EnableHighlighting="False">
            <dxm:MapItemStorage x:Name="storage"/>
        </dxm:VectorLayer>
        <dxm:InformationLayer>
            <dxm:InformationLayer.DataProvider>
                <dxm:BingSearchDataProvider BingKey="{Binding Source={StaticResource bingKey}}"
                                            GenerateLayerItems="False"
                                            SearchCompleted="SearchCompleted"/>
            </dxm:InformationLayer.DataProvider>
        </dxm:InformationLayer>
        <dxm:InformationLayer>
            <dxm:InformationLayer.DataProvider>
                <dxm:BingGeocodeDataProvider BingKey="{Binding Source={StaticResource bingKey}}"
                                             GenerateLayerItems="False"
                                             LocationInformationReceived="LocationInformationReceived"/>
            </dxm:InformationLayer.DataProvider>
        </dxm:InformationLayer>
        <dxm:InformationLayer>
            <dxm:InformationLayer.DataProvider>
                <dxm:BingRouteDataProvider x:Name="routeProvider" 
                                           BingKey="{Binding Source={StaticResource bingKey}}"
                                           GenerateLayerItems="False"
                                           RouteCalculated="RouteCalculated"/>
            </dxm:InformationLayer.DataProvider>
        </dxm:InformationLayer>
    </dxm:MapControl>
    
  • Create a helper class, which allows you to convert MapPushpin objects to RouteWaypoint and store the route using a MapPolyline object. Create a private member of this class in the MainWindow class.

    class RoutingHelper {
        List<MapPushpin> pushpins = new List<MapPushpin>();
        MapPolyline route = new MapPolyline() {
            Stroke = new SolidColorBrush(Color.FromArgb(0xFF, 0x8A, 0xFB, 0xFF)),
            StrokeStyle = new StrokeStyle() { Thickness = 3 }
        };
        List<RouteWaypoint> waypoints = new List<RouteWaypoint>();
        char currentLatter = 'A';
    
        public List<MapPushpin> Pushpins { get { return pushpins; } }
        public List<RouteWaypoint> Waypoints { get { return waypoints; } }
        public MapPolyline Route { get { return route; } set { route = value; } }
        public int Count { get { return pushpins.Count; } }
    
        public void BuildRoute(IEnumerable<GeoPoint> points) {
            route.Points.Clear();
            foreach (GeoPoint point in points)
                route.Points.Add(point);
        }
    
        public void AddItem(MapPushpin pushpin) {
            pushpins.Add(pushpin);
            waypoints.Add(new RouteWaypoint(
                ((LocationInformation)pushpin.Information).DisplayName,
                (GeoPoint)pushpin.Location)
            );
            pushpin.Text = (currentLatter++).ToString();
        }
    
        public void Clear() {
            route.Points.Clear();
            pushpins.Clear();
            waypoints.Clear();
            currentLatter = 'A';
        }
    }
    
  • Handle BingSearchDataProvider.SearchCompleted, BingGeocodeDataProvider.LocationInformationReceived and BingRouteDataProvider.RouteCalculated events. Also handle the MapPushpin.MouseLeftButtonDown event to add a location to waypoints.

    private void LocationInformationReceived(object sender, LocationInformationReceivedEventArgs e) {
        if ((e.Cancelled) && (e.Result.ResultCode != RequestResultCode.Success)) return;
        GenerateItems(e.Result.Locations);
    }
    
    private void SearchCompleted(object sender, BingSearchCompletedEventArgs e) {
        if (e.Cancelled || (e.RequestResult.ResultCode != RequestResultCode.Success)) return;
    
        if (e.RequestResult.SearchResults.Count != 0)
            GenerateItems(e.RequestResult.SearchResults);
        else
            GenerateItems(new LocationInformation[] { e.RequestResult.SearchRegion });
    }
    
    private void RouteCalculated(object sender, BingRouteCalculatedEventArgs e) {
        if (e.Cancelled) return;
    
        if (e.CalculationResult.ResultCode != RequestResultCode.Success) return;
        helper.BuildRoute(e.CalculationResult.RouteResults[0].RoutePath);
        UpdateStorage();
    }
    
    void GenerateItems(IEnumerable<LocationInformation> locations) {
        UpdateStorage();
        foreach (var location in locations) {
            MapPushpin pushpin = new MapPushpin() {
                Location = location.Location,
                Information = location
            };
            pushpin.MouseLeftButtonDown += pushpin_MouseLeftButtonDown;
            storage.Items.Add(pushpin);
        }
    }
    
    void UpdateStorage() {
        storage.Items.Clear();
        storage.Items.Add(helper.Route);
        foreach (MapPushpin pushpin in helper.Pushpins)
            storage.Items.Add(pushpin);
    }
    
    void pushpin_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
        MapPushpin pushpin = sender as MapPushpin;
        if (pushpin == null) return;
        e.Handled = true;
        helper.AddItem(pushpin);
        routeProvider.CalculateRoute(helper.Waypoints);
        pushpin.MouseLeftButtonDown -= pushpin_MouseLeftButtonDown;
    }
    
NOTE

If you run the application, and see a window with the following error message: ”The specified Bing Maps key is invalid. To create a developer account, refer to https://www.microsoft.com/en-us/maps/create-a-bing-maps-key”, refer to the following tutorial: How to: Get a Bing Maps Key.

See Also