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
Related Posts
-
C#: Read Text and JSON File Contents into Variable in Memory
18 Jun 2024 -
How to Cast an Int to an Enum in C#
17 Jun 2024 -
C#: How to Enumerate over Enum values and names
03 May 2024