Prototype of OpenStreetMap Silverlight Control using DeepEarth and Bing Maps SDK

I’ve decided to expand a little on using OpenStreetMap imagery with the new Bing Maps Silverlight Control in response to a commented posted by John O’Brien on my previous Display OpenStreetMap Imagery using Bing Maps Silverlight Control v1 post:

“Very close Chris but you will still need to enter a Bing Maps AppID. If however you create your own map from MapCore and don’t use the Bing Maps services then you don’t need credentials”

Yes, it is true that by just displaying the OpenStreetMap imagery on the Bing Maps Silverlight Control using a custom TileSource you still need to provide the control a Bing Maps Key (App ID). However, what if you inherited from the “MapCore” base class (the same one that the Bing Maps “Map” object inherits) and built out a full OpenStreetMap Map control?

Custom “OpenStreetMap” Control

I built out a test OpenStreetMap object that inherits from MapCore that automatically sets the Map Mode to a OpenStreetMapMode object that loads up the OpenStreetMap imagery automatically. This was some simple code to write, basically just extending only a little bit on top of what I posted in the previous post.

Here’s the code for the OpenStreetMap, OpenStreetMapMode and OpenStreetMapTileSource objects:

using System;
using Microsoft.Maps.MapControl;
using Microsoft.Maps.MapControl.Core;

namespace SilverlightApplication1
{
    public class OpenStreetMap : MapCore
    {
        public OpenStreetMap()
            : base()
        {
            this.Mode.SetView(new Location(), 2.0, 0.0, 0.0, false);
            this.Mode = new OpenStreetMapMode();
        }
    }

    public class OpenStreetMapMode : RoadMode
    {
        public OpenStreetMapMode()
            : base()
        {
            var tileLayer = (MapTileLayer)this.Content;
            tileLayer.TileSources.Clear();
            tileLayer.TileSources.Add(new OpenStreetMapTileSource());
        }
    }

    public class OpenStreetMapTileSource : TileSource
    {
        public OpenStreetMapTileSource()
            : base("http://tile.openstreetmap.org/{2}/{0}/{1}.png")
        {
        }

        public override System.Uri GetUri(int x, int y, int zoomLevel)
        {
            return new Uri(string.Format(this.UriFormat, x, y, zoomLevel));
        }
    }
}

And, here’s an example of using this new OpenStreetMap control:

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:map="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
    xmlns:local="clr-namespace:SilverlightApplication1"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
    <Grid x:Name="LayoutRoot">
        <local:OpenStreetMap Name="map">
            <local:OpenStreetMap.Children>
                <map:MapLayer>
                    <Image Source="BluePin.png" Opacity="0.8" Stretch="None" map:MapLayer.Position="42.16, -95"></Image>
                </map:MapLayer>
            </local:OpenStreetMap.Children>
        </local:OpenStreetMap>
    </Grid>
</UserControl>

What About Navigation Controls?

One side effect of creating this completely custom Map Control based off MapCore is that the other controls that the Map control includes automatically do not get displayed.

The Map control displays the MapControlNavigationBar control via the MapForeground object, however due to the MapForeground constructor that lets you tell it what MapBase object to attach to being marked “internal” is seems that it can’t be easily reused.

However, with a little help from the newest controls in developments within the DeepEarth project, you can fairly simply modify the Bing Maps Navigation control within the DeepEarth project to be used with the new “OpenStreetMap” control.

Here’s the code I worked up for a DeepEarth NavigationPanel for the OpenStreetMap control created earlier:

using System;
using System.Windows;
using DeepEarth.Client.BingMaps.Convertors;
using DeepEarth.Client.Common;
using GeoAPI.Geometries;
using GisSharpBlog.NetTopologySuite.Geometries;
using Microsoft.Maps.MapControl;
using Point = System.Windows.Point;
using Microsoft.Maps.MapControl.Core;

namespace NewDeepEarth.NavigationPanel
{
    public class NavigationPanel : DeepEarth.Client.Controls.NavigationPanel.NavigationPanel, IMapControl
    {
        private string mapName;

        public NavigationPanel()
        {
            Loaded += CoordinatePanel_Loaded;
        }

        public override double ZoomLevel
        {
            get
            {
                if (MapInstance != null)
                {
                    return MapInstance.ZoomLevel;
                }
                return 0;
            }
            set
            {
                if (MapInstance != null)
                {
                    MapInstance.ZoomLevel = value;
                }
            }
        }

        public override ICoordinate Center
        {
            get
            {
                if (MapInstance != null)
                {
                    return CoordinateConvertor.Convert(MapInstance.Center);
                }
                return new Coordinate(0, 0);
            }
            set
            {
                if (MapInstance != null)
                {
                    MapInstance.Center = CoordinateConvertor.ConvertBack(value);
                }
            }
        }

        #region IMapControl Members

        public string MapName
        {
            get { return mapName; }
            set
            {
                mapName = value;
                setMapInstance(MapName);
            }
        }

        public MapCore MapInstance { get; set; }

        public new void Dispose()
        {
            MapInstance = null;
            base.Dispose();
        }

        public override void PanMap(int deltaX, int deltaY)
        {
            if (MapInstance != null)
            {
                NewDeepEarth.Client.BingMaps.Utilities.Pan(deltaX, deltaY, MapInstance);
            }
        }

        #endregion

        private void CoordinatePanel_Loaded(object sender, RoutedEventArgs e)
        {
            setMapInstance(MapName);
        }

        private void setMapInstance(string mapname)
        {
            MapInstance = Utilities.FindVisualChildByName(Application.Current.RootVisual, mapname);
        }

    }
}

Also, hers a small utility method that I needed to modify slightly within the DeepEarth project to get the above NavigationPanel to work:

using Microsoft.Maps.MapControl.Core;
using Point = System.Windows.Point;

namespace NewDeepEarth.Client.BingMaps
{
    public static class Utilities
    {
        // Convert to accept Bing Maps "MapCore" instead of "Map" object
        public static void Pan(double deltaX, double deltaY, MapCore map) //Map map)
        {
            Point center = map.LocationToViewportPoint(map.Center);
            center.X = center.X + deltaX;
            center.Y = center.Y + deltaY;
            map.Center = map.ViewportPointToLocation(center);
        }
    }
}

Suggestion for the DeepEarth Preview Controls

One big suggestion I have for the DeepEarth projects new Preview Controls is to make the Bing Maps objects/libraries within the project use/accept MapCore or MapBase where ever it can instead of Map. This way as much of the DeepEarth code can be reused, without modification, when building a completely custom Map Control using the Bing Maps Silverlight SDK.

A perfect example of this are the modifications I needed to make to the NavigationPanel object and Utilities.Pan method posted above. By simply changing them from referencing/using Map to MapCore instead, they can not be used with any Map Control built using the Bing Maps Silverlight SDK.

Conclusion

Even though the above code works, it’s really just a prototype of what can be done using the current Preview controls within the DeepEarth project along with the new Bing Maps Silverlight Control. There is definitely some cool stuff to be done with both the Bing Maps Silverlight SDK and the DeepEarth project!

Anyway, here’s a download link to the full code of the project for the above code: OpenStreetMapDeepEarthPrototype.zip