Technology

Creating Striking Mapping Applications On Windows Phone 7 Using Bing Maps and CloudMade

Anthony Marshall
Anthony Marshall
20 Jan 2011
blog post featured image
<p>After presenting at the <a href="http://bingmapsuk.ning.com/" target="_blank">Bing Maps User Group</a> recently in which i discussed how to implement a custom mapping tile layer using the Deep Earth Silverlight control (<a href="http://deepearth.codeplex.com">http://deepearth.codeplex.com</a>) and the Cloudmade mapping service (<a href="http://www.cloudmade.com">http://www.cloudmade.com</a>) I began thinking about using this method to create a mapping application for Windows Phone 7 which more fits in with metro theme.</p> <p><a href="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2011/01/image.png"><img style="background-image: none; border-right-width: 0px; margin: 0px 0px 0px 150px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://techstudio-website-alt.azurewebsites.net/Content/blog/uploads/2011/01/image-thumb.png" width="229" height="422" /></a></p> <p>To begin with let’s have a look at the app we are going to build, as you can see the tiles being displayed are completely different to the standard Bing Maps tiles. Not only are you able to choose from thousands of pre-set map styles but you can also create your own too!</p> <p>Ok lets kick off building this, to begin you are going to need to head off to the <a href="https://www.bingmapsportal.com" target="_blank">Bing Maps Portal</a> to sign up and create yourself an application key. Once you have done this head off to <a href="http://cloudmade.com/" target="_blank">CloudMade</a> and create yourself a developer account. We are now in a position to actually write some code, create a new WP7 project and add a reference Microsoft.Phone.Controls.Maps.dll. We can now add some code to our MainPage.xaml as below.</p> <p>Add two namespace statements to the top of the page:</p> <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 494px; padding-right: 5px; height: 70px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">xmlns:maps=&quot;<span style="color: #8b0000">clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps</span>&quot;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">xmlns:core=&quot;<span style="color: #8b0000">clr-namespace:Microsoft.Phone.Controls.Maps.Core;assembly=Microsoft.Phone.Controls.Maps</span>&quot;</pre> <p>&#160;</p></pre> <br /> <pre><span style="font-family: arial">Then add a map control to the page also, setting the map mode as below:</span></pre> <p>&#160;</p> <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 494px; padding-right: 5px; height: 186px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;maps:Map CredentialsProvider=&quot;<span style="color: #8b0000">{Enter Your Bing Maps Key Here}</span>&quot;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">VerticalAlignment=&quot;<span style="color: #8b0000">Stretch</span>&quot; HorizontalAlignment=&quot;<span style="color: #8b0000">Stretch</span>&quot; Grid.Row=&quot;<span style="color: #8b0000">1</span>&quot; Name=&quot;<span style="color: #8b0000">map1</span>&quot; &gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;maps:Map.Mode&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;core:MercatorMode&gt;&lt;/core:MercatorMode&gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/maps:Map.Mode&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;/maps:Map&gt;</pre> <p>&#160;</p></pre>

<br /><span style="font-family: arial">If you run the application at this point you will not see a great deal of anything, in effect what we have done is turn off the standard Bing Map tiles. We now need to create our custom tile </span><span style="font-family: arial">provider to serve the tiles from CloudMade to our app using the code below</span><span style="font-family: arial">:</span>

<br /> <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 494px; padding-right: 5px; height: 749px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> CloudMadeTileSource : TileSource</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">{</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">private</span> <span style="color: #0000ff">const</span> <span style="color: #0000ff">string</span> _tilePath= &quot;<span style="color: #8b0000">http://{S}.tile.cloudmade.com/{creds}/{style}/256/{Z}/{X}/{Y}.png</span>&quot;;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> Random _rand = <span style="color: #0000ff">new</span> Random();</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> <span style="color: #0000ff">string</span>[] TilePathPrefixes = <span style="color: #0000ff">new</span>[] { &quot;<span style="color: #8b0000">a</span>&quot;, &quot;<span style="color: #8b0000">b</span>&quot;, &quot;<span style="color: #8b0000">c</span>&quot; };</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> CloudMadeCredentialsProvider { <span style="color: #0000ff">get</span>; <span style="color: #0000ff">set</span>; }</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> CloudMadeMapStyleId { <span style="color: #0000ff">get</span>; <span style="color: #0000ff">set</span>; }</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> Uri GetUri(<span style="color: #0000ff">int</span> x, <span style="color: #0000ff">int</span> y, <span style="color: #0000ff">int</span> zoomLevel)</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> {</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">string</span> url = <span style="color: #0000ff">string</span>.Empty;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">string</span> prefix = <span style="color: #0000ff">string</span>.Empty;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> prefix = TilePathPrefixes[_rand.Next(3)];</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = _tilePath;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #008000">//Randomize to different OSM Servers based on URL prefix</span></pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{creds}</span>&quot;, CloudMadeCredentialsProvider);</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{style}</span>&quot;, CloudMadeMapStyleId);</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{S}</span>&quot;, prefix);</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{Z}</span>&quot;, zoomLevel.ToString());</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{X}</span>&quot;, x.ToString());</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> url = url.Replace(&quot;<span style="color: #8b0000">{Y}</span>&quot;, y.ToString());</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Uri(url);</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> }</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">}</pre> </pre>

<br />Here we are inheriting from the TileSource class and overiding the GetUri method which gives the mapping control the uri to the image file for a tile on the map. this is done by taking a URL which has placeholders for the important pieces of information the CloudMade system requires which is described very well on the <a href="http://developers.cloudmade.com/projects/tiles/documents" target="_blank">CloudMade site</a>. we also have properties for setting the CloudMade credentials and style id so these can be set in xaml.

<p>We can now add a a reference to this class in our xaml as so:</p> <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 492px; padding-right: 5px; height: 52px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">xmlns:local=&quot;<span style="color: #8b0000">clr-namespace:StylisedMap</span>&quot;</pre> <p>&#160;</p></pre> <br /> <pre><span style="font-family: arial">Then add the TileSource to the map in our xaml:</span></pre> <p>&#160;</p> <pre style="border-bottom: #cecece 1px solid; border-left: #cecece 1px solid; padding-bottom: 5px; background-color: #fbfbfb; min-height: 40px; padding-left: 5px; width: 495px; padding-right: 5px; height: 418px; overflow: auto; border-top: #cecece 1px solid; border-right: #cecece 1px solid; padding-top: 5px"><pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;maps:Map CredentialsProvider=&quot;<span style="color: #8b0000">{Enter Your Bing Maps Key Here}</span>&quot;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> VerticalAlignment=&quot;<span style="color: #8b0000">Stretch</span>&quot; HorizontalAlignment=&quot;<span style="color: #8b0000">Stretch</span>&quot;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">Grid.Row=&quot;<span style="color: #8b0000">1</span>&quot; Name=&quot;<span style="color: #8b0000">map1</span>&quot; &gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;maps:Map.Mode&gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;core:MercatorMode&gt;&lt;/core:MercatorMode&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/maps:Map.Mode&gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;maps:MapTileLayer&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;maps:MapTileLayer.TileSources&gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;local:CloudMadeTileSource</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">CloudMadeCredentialsProvider=&quot;<span style="color: #8b0000">{Enter Your CloudMade Key Here}</span>&quot;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">CloudMadeMapStyleId=&quot;<span style="color: #8b0000">{Enter Your Chosen Map Style Id Here}</span>&quot; /&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/maps:MapTileLayer.TileSources&gt;</pre> <p>&#160;</p> <pre style="background-color: #fbfbfb; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px"> &lt;/maps:MapTileLayer&gt;</pre> <p>&#160;</p> <pre style="background-color: #ffffff; margin: 0em; width: 100%; font-family: consolas,&#39;Courier New&#39;,courier,monospace; font-size: 12px">&lt;/maps:Map&gt;</pre> </pre>

<br />If you now build and run the application you have a working Bing Map Windows Phone Application with custom map tiles. Enjoy!!

<p>You can download the <a href="http://wp7bingmapscloudmade.codeplex.com/" target="_blank">sample project here</a>.</p>
Close chatbot
Open chatbot
Open chatbot