<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Tutorials</title><link>http://www.reimers.dk:80/tutorials</link><description>Tutorials</description><item><title>Using Linq2Rest as a Client</title><link>http://www.reimers.dk:80/tutorials/using-linq2rest-as-a-client</link><description>&lt;p&gt;In this &lt;a target="_blank" href="http://www.reimers.dk/tutorials/using-linq2rest"&gt;tutorial&lt;/a&gt; I explained how to use &lt;a target="_blank" href="https://bitbucket.org/jjrdk/linq2rest"&gt;Linq2Rest&lt;/a&gt; in an ASP.NET or ASP.NET MVC application. This time we will be looking at how to use Linq2Rest in a client application in order to generate a web request to retrieve the results of a LINQ query.&lt;/p&gt;
&lt;p&gt;Before we go any further, I should warn you that the tutorial will not go into the details about types, interfaces, projections and LINQ queries. It is assumed that you understand how to write LINQ queries as well deserializing web responses.&lt;/p&gt;
&lt;p&gt;The request generation and invocation is handled by the RestContext&amp;lt;T&amp;gt; class. The constructor takes two arguments: an IRestClient and an ISerializerFactory. The IRestClient interface is a wrapper around a web request invocator, i.e. a class which can download a result from a REST service. The project includes a public RestClient class which will request JSON data from the service endpoint that you define, but it is recommended that you write your own implementation. I am not going to go into the expectations when it comes to requesting a resource from a RESTful service. You will have to look know what service you wish to depend on.&lt;/p&gt;
&lt;p&gt;The ISerializerFactory is a wrapper around a serializer which will be what converts the downloaded data back into an object (or more likely, a list of objects). It may seem a bit convoluted to require a serializer factory, why not just use a serializer? The reason is that the context can live longer than one request and each query can return a different object type, because Linq2Rest supports projections (i.e. Select queries), which means that the result is not known in advance. For this reason the serializer factory must be capable of providing a serializer for the expected response type.&lt;/p&gt;
&lt;p&gt;It should be obvious, but I am going to say it anyway, there has to be a corelation between what your IRestClient downloads and what the serializer can handle. So don't provide an IRestClient that downloads JSON if you are going to provide XML serializers.&lt;/p&gt;
&lt;p&gt;To set up your context, simply create an instance of the RestContext class, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;IRestClient restClient; // Create an instance of your concrete implementation.
ISerializerFactory serializerFactory; // Create an instance of your concrete implementation.
RestContext&amp;lt;yourresourcetype&amp;gt; provider = new RestContext&amp;lt;yourresourcetype&amp;gt;(restClient, serializerFactory);&lt;/pre&gt;
&lt;p&gt;Once you have created your context, you can start querying the Query property, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;var result = provider.Query
	.Where(x =&amp;gt; x.Value &amp;lt;= 3)
	.Select(x=&amp;gt; new { x.Value, x.Content })
	.OrderBy(x=&amp;gt; x.Value)
	.Skip(1)
	.Take(1);&lt;/pre&gt;
&lt;p&gt;What happens when this query gets executed is, that Linq2Rest will generate a web request using the provided IRestClient and download the response from the web service. The response will be deserialized and returned as the requested type. This means that the full round trip of requesting a resource from a web service is encapsulated. As long as the end point supports OData style parameters, the response can be limited to what is required to satisfy the query, which will most likely result in a smaller download, since the filtering can be applied on the server.&lt;/p&gt;
&lt;p&gt;In the example above the query includes a projection, which means that the resulting type is an anonymous type. The passed serializer factory must be able to deserialize into an anonymous type. The &lt;a target="_blank" href="http://nuget.org/packages/linq2rest.mvc"&gt;Linq2Rest.Mvc&lt;/a&gt; package includes a SimpleAnonymousTypeSerializer which you can use to generate anonymous types from a projected response. It is called simple because it handles built in CLR types, but provides to assurances that it can handle complex object graphs.&lt;/p&gt;
&lt;p&gt;Linq2Rest is published under &lt;a target="_blank" href="http://www.opensource.org/licenses/MS-PL"&gt;Microsoft Public License&lt;/a&gt; and can be found on &lt;a target="_blank" href="https://bitbucket.org/jjrdk/linq2rest"&gt;BitBucket&lt;/a&gt; and &lt;a target="_blank" href="http://nuget.org/packages/linq2rest"&gt;Nuget&lt;/a&gt; (The Linq2Rest.Mvc project on &lt;a target="_blank" href="http://nuget.org/packages/linq2rest.mvc"&gt;Nuget&lt;/a&gt;).&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
     SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Sun, 05 Feb 2012 11:26:36 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/using-linq2rest-as-a-client</guid></item><item><title>Using Linq2Rest</title><link>http://www.reimers.dk:80/tutorials/using-linq2rest</link><description>&lt;p&gt;When I published the release version of Linq2Rest, I knew that this was only the technical side of the project. In order for a project to be useful (or even used), user must be able to get started with it. I've tried to keep the API as simple as possible. Primarily because it makes it easier to use, but also because it makes it easier to manage from a semantic versioning perspective.&lt;/p&gt;
&lt;p&gt;First of all, what is Linq2Rest? Linq2Rest parses a set of query parameters conforming to the &lt;a target="_blank" href="http://www.odata.org/"&gt;OData protocol&lt;/a&gt; and converts them into a LINQ filter, which can be used to filter a data source. For a simple data source such as a List&lt;t&gt; or T[] it works like any other LINQ query, but if you use it with ORM frameworks, they can apply it as a SQL query to the database. This means that you can expose your data in a much richer way to your users than merely by relying on some obscure parameters written in your documentation, that they will never read. Linq2Rest also works on the client side by exposing a LINQ provider that will generate OData compliant web requests to a given host.&lt;/t&gt;&lt;/p&gt;
&lt;p&gt;So what is required to parse a given request into a LINQ filter? Obviously you must be running a web site (ASP.NET) that the user can request data from. ASP.NET MVC is also supported, more on that later. To apply the LINQ filter to your data source, simply use the Filter extension method on your LINQ compatible data source, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;var filteredSource = source.Filter(Request.Params);&lt;/pre&gt;
&lt;p&gt;Linq2Rest parses the passed NameValueCollection (in this case the parameters of the current request) and gets all OData parameters and creates an expression tree from them which is applied to the source. Note that the returned filteredSource, is an IEnumerable&lt;object&gt; and not necessarily the same as your original source, since OData supports data projection and the exact return type cannot be known before the filter is applied.&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;If you are running an ASP.NET MVC site, your action can also reference the current request directly and retrieve the query parameters, but it is not considered very good practice. Instead it is recommended that you add an IModelFilter&lt;t&gt; to the actions where you wish to apply filtering. So your action could look something like this:&lt;/t&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public ActionResult Index(IModelFilter&amp;lt;yourobjecttype&amp;gt; filter, IEnumerable&amp;lt;yourobjecttype&amp;gt; source)
{
    var filteredSource = source.Filter(filter);
    return View(filteredSource);
}&lt;/pre&gt;
&lt;p&gt;In order for the MVC Framework to create an IModelFilter&lt;t&gt; for your request, you will need to add a model binder to your MVC application. The Linq2Rest.Mvc nuget package gives you access to a model binder which performs this binding for you, all you need to do is add it to your application like any other model binder:&lt;/t&gt;&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Application_Start()
{
	AreaRegistration.RegisterAllAreas();

	RegisterGlobalFilters(GlobalFilters.Filters);
	RegisterRoutes(RouteTable.Routes);

	var binder = new ModelFilterBinder&amp;lt;yourobjecttype&amp;gt;(new ParameterParser&amp;lt;yourobjecttype&amp;gt;());
        ModelBinders.Binders.Add(typeof(IModelFilter&amp;lt;yourobjecttype&amp;gt;), binder);
}&lt;/pre&gt;
&lt;p&gt;The model binder will be invoked when a request is received and will create the filter for the given request, which you can then apply as shown above.&lt;/p&gt;
&lt;p&gt;Linq2Rest is published under &lt;a target="_blank" href="http://www.opensource.org/licenses/MS-PL"&gt;Microsoft Public License&lt;/a&gt; and can be found on &lt;a target="_blank" href="https://bitbucket.org/jjrdk/linq2rest"&gt;BitBucket&lt;/a&gt; and &lt;a target="_blank" href="http://nuget.org/packages/linq2rest"&gt;Nuget&lt;/a&gt; (The Linq2Rest.Mvc project on &lt;a target="_blank" href="http://nuget.org/packages/linq2rest.mvc"&gt;Nuget&lt;/a&gt;).&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
     SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Sat, 21 Jan 2012 23:03:48 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/using-linq2rest</guid></item><item><title>Getting To Where You Want To Be</title><link>http://www.reimers.dk:80/tutorials/getting-to-where-you-want-to-be</link><description>&lt;p&gt;In &lt;a href="http://www.reimers.dk/tutorials/where-am-i-and-how-do-i-get-there" title="Where Am I And How Do I Get There" target="_blank"&gt;another tutorial&lt;/a&gt; I talk about geocoding, which is performed by the GoogleGeocoder class. This class has three general methods for geocoding:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Geocode&lt;/li&gt;
&lt;li&gt;ReverseGeocode&lt;/li&gt;
&lt;li&gt;GetDirections&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these methods returns a GoogleResult, which encapsulates the result of the request as well as any return values. Just like with any web service response it is prudent to verify the status of the operation. If the operation is successful and a result has been returned, its data can then be used.&lt;/p&gt;
&lt;p&gt;Once you have verified the result, it is likely that you will be using it to show on a map. The returned data is not returned directly as overlays, because I did not want to make any assumptions about what it was to be used for, or indeed how it was going to be displayed. I wanted to leave it up to you to extract the data from the result and display it in your way, letting Intellisense and the documentation guide you. The result data is laid out in the same way Google returns the directions from &lt;a href="http://code.google.com/apis/maps/documentation/directions/#JSON" target="_blank"&gt;its web service&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the impatient among you who do not want to spend time reading documentation or read the Intellisense suggestions, here is a shortcut, that was added in version 5.2. The route can be passed to the constructor of a Polyline and it will perform the work of creating the polyline for you. Like so:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;var geocoder = new GoogleGeocoder();
var result = geocoder.GetDirections("Bratislava, Slovakia", "Trnava, Slovakia");
if (result.Status == GeocodeStatus.OK &amp;amp;&amp;amp; result.Directions != null)
{
	foreach (var routeLine in result.Directions.Routes.Select(route =&amp;gt; new Polyline(route)))
	{
		map.Overlays.Add(routeLine);
	}
}
&lt;/pre&gt;
&lt;p&gt;As always, when using the geocoding service, then make sure you cache the results. First of all it speeds of rendering the page, but you also won't run into the situation where Google stops responding because you have exceeded your daily limit. The best practice is to do it once application wide and then reuse the result. I'll leave this up as to how it best suits your application.&lt;/p&gt;</description><pubDate>Sun, 23 Oct 2011 20:26:58 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/getting-to-where-you-want-to-be</guid></item><item><title>Where Am I And How Do I Get There</title><link>http://www.reimers.dk:80/tutorials/where-am-i-and-how-do-i-get-there</link><description>&lt;p&gt;The geocoding namespace has gotten a major overhaul in this latest revision. There are many new features and many new classes to expose these features. However the changes also mean that some code may break, so be aware of this when upgrading.&lt;/p&gt;
&lt;p&gt;The refactoring means that all geocoding results are delivered in a GoogleResult class. This class was previously only used for geocoding, but is now the default response for all services in the geocoding namespace.&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;So what are these new features?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Reverse Geocoding&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Reverse geocoding is one exciting new service that has been included.Recently Google announced reverse geocoding. So now you can click on a map and get the address. The map control has previously used the&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;a href="http://geonames.org/" title="Geonames" target="_blank" style="color: #000000;"&gt;Geonames&lt;/a&gt; webservice to perform reverse geocoding. This was a fairly rudimentary service, which only reversed geocoded down to city level. Google's service delivers address information, so obviously that is now used.&lt;/p&gt;
&lt;p&gt;To perform a reverse geocoding request simply call the ReverseGeocode method of the GoogleGeocoder (Reimers.Map.Geocoding.GoogleGeocoder), and either pass the latitude longitude coordinates as double values, or pass a GoogleLatLng object. This will return a GoogleResult object with the address if the search was successful.&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;var geocoder = new GoogleGeocoder();
GoogleResult result = geocoder.ReverseGeocode(51.5, 0.0);

if (result.Status == GeocodeStatus.G_GEO_SUCCESS)
{
	foreach (Location loc in result.Locations)
	{
		Address returnedAddress = loc.Address;
	}
}
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Directions&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Now that you know where you are, you may want to know where you are going.&lt;/p&gt;
&lt;p&gt;Apart from reverse geocoding the control also implements Google's directions service. Previously you could request a route and get a collection of overlays. This has been obsoleted by the new GoogleDirections class.While it may seem more complicated at first, it will give you total control over your routing directions.&lt;/p&gt;
&lt;p&gt;The GoogleDirections class gives you information (summary, distance, duration and copyright info) about the total trip you have requested. It also contains an enumeration of routes (normally only one is returned). The route information is contained in the GoogleRoute class.&lt;/p&gt;
&lt;p&gt;Like the GoogleDirections the GoogleRoute class gives you some information about the route. It also contains every step of the way as GoogleSteps. This class gives you the detailed driving or walking directions.&lt;/p&gt;
&lt;p&gt;So instead of simply adding the returned overlays like before, you can now loop through the various steps on the route and present them as you want.&lt;/p&gt;
&lt;p&gt;Serialization&lt;/p&gt;
&lt;p&gt;If you want to make use of all these new features without having to post the page back to the server, the control now includes classes to help you with the JSON serialization/deserialization of the information. This means that you can serve the information from a ScriptService and use it directly in your clientside script.&lt;/p&gt;
&lt;p&gt;You will find numerous JavaScriptConverters in the Reimers.Map.Json.Converters namespace. These can either be registered in your web.config file, like so:&lt;/p&gt;
&lt;p&gt;XML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;jsonserialization&amp;gt;
	&amp;lt;converters&amp;gt;
		&amp;lt;add name="GoogleDirectionsConverter" type="Reimers.Map.Json.Converters.GoogleDirectionsConverter"/&amp;gt;
	&amp;lt;/converters&amp;gt;
&amp;lt;/jsonserialization&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Another way to access is from the newly exposed MapUtils class, that has a public JsonSerializer property that will give you a serializer with the converters already registered.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Sun, 23 Oct 2011 16:36:40 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/where-am-i-and-how-do-i-get-there</guid></item><item><title>Displaying Infowindows</title><link>http://www.reimers.dk:80/tutorials/displaying-infowindows</link><description>&lt;p&gt;InfoWindows are handled differently in version 3 of Google's map API than in version 2. In version 3 they are overlays in their own right, which means that it is possible to display several infowindows at the same time. The price for this flexibility is that the displayed infowindows have to be managed separately and explicitly&lt;/p&gt;
&lt;p&gt;Where version 2 had methods on overlays to display infowindows, version 3 requires that the infowindow is created as a separate overlay and displayed on the map and destroyed when it is no longer needed. When developing a map control it is necessary to consider the potential memory leaks, so for the moment info windows created from the server, are destroyed when they are closed. Infowindows will survive a postback to the server, but if they are closed, they will be removed from the overlay collection.&lt;/p&gt;
&lt;p&gt;To display an infowindow it should be created and added to the overlays collection like any other overlay, like so:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:Map runat="server" ID="map" Width="600" Height="400" Zoom="10"&amp;gt;
	&amp;lt;Center Latitude="51.477" Longitude="0.0" /&amp;gt;
	&amp;lt;Overlays&amp;gt;
		&amp;lt;Reimers:InfoWindow Content="Hello World"&amp;gt;
			&amp;lt;Position Latitude="51.47" Longitude="0.01" /&amp;gt;
		&amp;lt;/Reimers:InfoWindow&amp;gt;
	&amp;lt;/Overlays&amp;gt;
&amp;lt;/Reimers:Map&amp;gt;
&lt;/pre&gt;
&lt;p&gt;They can also be created in response to an event, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	map.OverlayClick += map_OverlayClick;
}

void map_OverlayClick(object sender, OverlayEventArgs e)
{
	var infowindow = new InfoWindow
		{
			Position = e.Overlay.Bounds.Center.ToLatLng(),
			Content = "Hello World"
		};
	e.MapCommand = e.Map.AddOverlay(infowindow, true);
}
&lt;/pre&gt;
&lt;p&gt;Notice how the AddOverlays method uses an extra parameter, which defines that the overlay should be persistent in the overlay collection. The method returns a JavaScript which displays the infowindow, but behind the scenes the overlay collection is also updated. This means that if the page is submitted before the infowindow is closed, it will remain on the map.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Sun, 09 Oct 2011 22:06:04 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/displaying-infowindows</guid></item><item><title>Handling Map Events</title><link>http://www.reimers.dk:80/tutorials/handling-map-events</link><description>&lt;p&gt;Once you have added some markers to your map you will want them to do something other than merely sit there, i.e. you will want them to react to some event or other. Most commonly you will want them to display a little infowindow with some text, but anything is of course possible.&lt;/p&gt;
&lt;p&gt;In this tutorial I will show how to handle events using the Google Maps .NET Control. The first part will show the serverside event handling using callbacks which is available for both the free and the licensed control. Afterwards I will describe the use of clientside event handling which is only available in the licensed control (except for click events). While events may be handled serverside the page is not actually posted back to the server. Instead a callback is made to the server to handle the event, making the operation very light in terms of traffic, but on the other hand not able to alter the page's viewstate. This means that any objects added, removed or changed must be noted elsewhere until such a time as the page is actually posted back and the changes to the viewstate can be made permanent. Also note that only the GoogleMap class has its own events, so overlay's events are handled by the map, except for clientside event handling described below.&lt;/p&gt;
&lt;p&gt;Like for any ASP.NET control event handlers can be tied to events in either the markup or in the code behind. The easiest is of course in the markup if you ask me. To add an event handler in the markup all you need to do is ensure that the Page directive has the AutoEventWireup tag set to true, like this:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;%@ Page Language="C#" AutoEventWireup="true" CodeFile="mappage.aspx.cs" Inherits="mappage" %&amp;gt;&lt;/pre&gt;
&lt;p&gt;After that you can set the name of the event handler method in the markup for the Google Maps .NET Control, like so:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:GoogleMap ID="GoogleMap" runat="server" OnClick="MapClick" /&amp;gt;&lt;/pre&gt;
&lt;p&gt;Another way to do it is to assign the event handler in the code behind, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	GoogleMap.Click += new EventHandler&amp;lt;CoordinatesEventArgs&amp;gt;(MapClick);
}
&lt;/pre&gt;
&lt;p&gt;This ties the MapClick method as the handler to the map's click event. You will find all the delegates and their signatures in the accompanying documentation. Generally the delegates follow the standard event handler signature with the event args holding a reference to the map and a string call MapCommand. The MapCommand string is the most important as the result of the callback must be written to this string in order to be handled by the client. You can of course do any kind of serverside operation you want, but any results that are to be fed back to the client must be sent to the MapCommand as a string of JavaScript. The control includes many common map operations as methods, which will create the necessary JavaScript code, so there is no need to worry if you don't know JavaScript.&lt;/p&gt;
&lt;p&gt;To actually handle the event the MapClick method must do some sort of operation. A simple thing to do would be to display the point clicked by the map, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;void MapClick(object sender, CoordinatesEventArgs e)
{
	e.MapCommand = Map.OpenInfoWindowHTML(
		Position,
		string.Format("Lat: {0}&lt;br /&gt;Lng: {1}", Position.Latitude.ToString(), Position.Longitude.ToString()));
}
&lt;/pre&gt;
&lt;p&gt;If you create an event handler using the instructions above you should see an infowindow pop up when you click the map showing the coordinates clicked. As mentioned above the control includes numerous methods for creating the necessary JavaScript code. Above is used the map's OpenInfoWindowHTML method with takes a GoogleLatLng argument and a string argument. The string should be properly formatted HTML - due to limitations you should use double quotes in your HTML as single quotes are not processed and may result in an error.&lt;/p&gt;
&lt;p&gt;Of course you may want to create more elaborate processing in your events, such as database lookups etc, but as long as you set up the event handler properly and remember that all output must be assigned as JavaScript to the MapCommand string there should be no problem.&lt;/p&gt;
&lt;h3&gt;Clientside event handling&lt;/h3&gt;
&lt;p&gt;While the serverside event handling using AJAX can be more elaborate the clientside event handling wins when only simple actions are necessary. While clientside event handling in theory supports all the JavaScript language and so allows for some elaborate coding I would recommend using the serverside handlers if elaborate coding is required. Clientside handlers are great where you want to perform the same relatively simple task numerous times without the need to constantly fetch information on the server (thereby lightening the load on the server), for example showing the same text in an infowindow when a marker is clicked.&lt;/p&gt;
&lt;p&gt;The GoogleMap class and the GoogleMarker class include a ClientSideHandler property that lets you set a clientside handler for the events as a string. The handler should be a string of JavaScript to be executed. It will be wrapped into a function so there is no need to write anything except the JavaScript to be executed. For example if you want to display an infowindow every time a marker is clicked you would add the string to the marker's clientside click handler, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	GoogleMarker m = new GoogleMarker("myMarker", 55, 0);
	m.ClientSideHandlers.OnClick = m.OpenInfoWindowHTML(GoogleMap, "You clicked me");
}
&lt;/pre&gt;
&lt;p&gt;Remember that the control includes numerous methods to generate the necessary JavaScript for the most common functions for you. For example above I used the OpenInfoWindowHTML method of the marker to generate the necessary JavaScript.&lt;/p&gt;
&lt;p&gt;Note that when assigning clientside handlers they are assigned to the specific object and not to all objects of that class. As opposed to serverside handling where one method handles all overlay clicks for example (by discerning which overlay was clicked and returning that overlay as an argument) the clientside handler is specific to the individual overlay.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 05 Sep 2011 18:42:08 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/handling-map-events</guid></item><item><title>Targeting Version 3 of Google Maps</title><link>http://www.reimers.dk:80/targeting-version-3-of-google-maps</link><description>&lt;p&gt;The Google Maps API has moved to version 3 some time ago, and it has taken some time to update the map control. There is now a build that targets the new API and implements most of the features in the version of the control targeting version 2 of the Google Maps API. Given that the control is targeting a new underlying API there are bound to be some changes to the API of the Google Maps .NET Control, but I have strived to keep the changes to a minimum. But do note that there will be several breaking changes if you update your application. The class names used in the control are designed to mirror the class names in the underlying map API. If you find that the documentation for this map control is lacking, please read &lt;a target="_blank" href="http://code.google.com/apis/maps/documentation/javascript/reference.html"&gt;Google's documentation&lt;/a&gt; and assume that the control allows and supports the documented behavior.&lt;/p&gt;
&lt;p&gt;The control is open source and available for both commercial and private use.&lt;/p&gt;
&lt;p&gt;The new control can be used with both Visual Studio Express as well as the normal versions of Visual Studio, targeting either .NET 3.5 or .NET 4.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;Adding the Map&lt;/p&gt;
&lt;p&gt;To add a map to your ASP.NET page you will first need to add an assembly reference&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;%@ Register Assembly="Reimers.Google.Map" Namespace="Reimers.Google.Map" TagPrefix="Reimers" %&amp;gt;&lt;/pre&gt;
&lt;p&gt;On the part of the page that you want to add your map you can now add the control using the standard ASP.NET control syntax:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:Map runat="server"&amp;gt;&amp;lt;/Reimers:Map&amp;gt;
&lt;/pre&gt;
&lt;p&gt;This will create a small 256px x 256px map with the default map types and controls. You can alter the default state by setting map properties either as attibute values or internal elements. Internal elements are used for complex types, where simple property values are generally set using attributes. The control supports the various map controls defined by the API. The code below shows how to add a MapTypeControl to the map.&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:Map runat="server" Width="600" Height="400" DefaultMapType="Terrain"&amp;gt;
	&amp;lt;Center Latitude="51.477" Longitude="0.0" /&amp;gt;
	&amp;lt;MapControls&amp;gt;
		&amp;lt;Reimers:MapTypeControl Position="Top_Right" ControlStyle="Dropdown_Menu" /&amp;gt;
	&amp;lt;/MapControls&amp;gt;
&amp;lt;/Reimers:Map&amp;gt;
&lt;/pre&gt;
&lt;p style="font-weight: bold;"&gt;Overlays&lt;/p&gt;
&lt;p&gt;The same syntax applies for adding overlays to the control. Currently the documented overlays are supported by the control.&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:Map runat="server" Width="600" Height="400" DefaultMapType="Terrain"&amp;gt;
	&amp;lt;Center Latitude="51.477" Longitude="0.0" /&amp;gt;
	&amp;lt;Overlays&amp;gt;		
		&amp;lt;Reimers:Rectangle FillColor="Green" FillOpacity="0.5" BorderColor="Red" BorderOpacity="0.9"&amp;gt;
			&amp;lt;NorthEast Latitude="51.48" Longitude="0.1" /&amp;gt;
			&amp;lt;SouthWest Latitude="51.47" Longitude="-0.1" /&amp;gt;
		&amp;lt;/Reimers:Rectangle&amp;gt;
		&amp;lt;Reimers:Polyline Color="Green" Width="5"&amp;gt;
			&amp;lt;Points&amp;gt;
				&amp;lt;Reimers:LatLng Latitude="51.477" Longitude="0.0" /&amp;gt;
				&amp;lt;Reimers:LatLng Latitude="51" Longitude="1.0" /&amp;gt;
			&amp;lt;/Points&amp;gt;
		&amp;lt;/Reimers:Polyline&amp;gt;
		&amp;lt;Reimers:Circle Radius="500" FillOpacity="0.3"&amp;gt;
			&amp;lt;Center Latitude="51.477" Longitude="0.0" /&amp;gt;
		&amp;lt;/Reimers:Circle&amp;gt;
	&amp;lt;/Overlays&amp;gt;
&amp;lt;/Reimers:Map&amp;gt;
&lt;/pre&gt;
&lt;p style="font-weight: bold;"&gt;AdSense Support&lt;/p&gt;
&lt;p&gt;The new map API also supports displaying location relevant ads directly on the map as a map control. The control provides an abstraction over the AdSense API, but assuming you have an AdSense publisher ID you can add an ad block by adding a control to the MapControls collection, like so:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:Map runat="server"&amp;gt;
	&amp;lt;MapControls&amp;gt;
		&amp;lt;Reimers:AdSenseControl Position="Right_Center" PublisherID="pub-YourOwnIdGoesHere"/&amp;gt;
	&amp;lt;/MapControls&amp;gt;
&amp;lt;/Reimers:Map&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The new control has a more open clientside (JavaScript) API, which will make it easier to update the control clientside and continue working with those changes on the server. Interacting with the clientside code will be dealt with in a later post.&lt;/p&gt;
&lt;p&gt;The control targeting version 3 of Google Maps can be downloaded from &lt;a href="http://www.reimers.dk/google-maps-.net-control-for-v3-maps-beta"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Thu, 01 Sep 2011 21:56:53 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/targeting-version-3-of-google-maps</guid></item><item><title>Your First Map</title><link>http://www.reimers.dk:80/tutorials/your-first-map</link><description>&lt;p&gt;The Google Maps .NET Control is designed to render with a minimum of user input and almost works as drag and drop. If you are using Visual Studio 2005 or Visual Web Developer Express you can add the control to your toolbox and then drag and drop it on to the web page where you want a map. Visual Studio or Visual Web Developer Express will add the following code to your page:&lt;/p&gt;
&lt;p&gt;At the top of the page the assembly will be registered for use on the page.&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;%@ register assembly="GoogleMap" namespace="Reimers.Map" tagprefix="Reimers" %&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Somewhere on the page where you want your map to be you will have:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:GoogleMap ID="GoogleMap1" runat="server" /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;One of the only requirements to get a map key from Google (get it here) which is to be used to verify the user's access to the underlying JavaScript API. This GoogleKey property of the control needs to be assigned this value. This can be done either in the markup or in the code behind.&lt;/p&gt;
&lt;p&gt;If you assign it directly in the markup you should write your map tag as:&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:GoogleMap ID="GoogleMap1" runat="server" GoogleKey="Googlesreallylongkey" /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;If you write it in your code behind you can write as follows:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	GoogleMap1.GoogleKey = "Googlesreallylongkey";
}
&lt;/pre&gt;
&lt;p&gt;One thing I like to do is to store the key in the Web.Config file. That way I don't have to cut and paste a huge key every time I want to add a map. I can simply grab it from the Web.Config using the ConfigurationManager class, like this:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	GoogleMap1.GoogleKey = ConfigurationManager.AppSettings["MapKey"];
}
&lt;/pre&gt;
&lt;p&gt;To size your map set the Width and Height properties to the desired size. I recommend doing this is the markup but you are free to do it in the code behind.&lt;/p&gt;
&lt;p&gt;The final thing you need to set is the starting location of your map. This is done using the Latitude, Longitude and Zoom properties. Latitude and Longitude take a double value (System.Double) and the Zoom property takes an integer (System.Integer). The licensed version has an additional Center property where the map center can be set directly using a GoogleLatLng object. One thing to note when setting the map location is that if it is set in the markup or during a postback it overrides the map position before the postback. The map is programmed to maintain its position through postbacks, so I would advise that any position set during the page load routine be done only if the page has not been posted back, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;if (!Page.IsPostBack)
{
	GoogleMap1.Latitude = 55;
	GoogleMap1.Longitude = 0;
	GoogleMap1.Zoom = 10;
}
&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public partial class demos_mapdemo : System.Web.UI.Page
{
	protected void Page_Load(object sender, EventArgs e)
	{
		GMap.GoogleKey = ConfigurationManager.AppSettings["MapKey"];
		GMap.Width = new Unit(100, UnitType.Percentage);
		GMap.Height = new Unit(500, UnitType.Pixel);
		GMap.MapControls.Add(new Reimers.Map.Controls.GoogleSmallMapTypeControl("smc"));
		GMap.MapControls.Add(new Reimers.Map.Controls.GoogleSmallMapControl("sc"));
		GMap.RenderDelay = 600;

		if (!Page.IsPostBack)
		{
			GMap.Latitude = 45;
			GMap.Longitude = -36;
			GMap.Zoom = 3;

			GoogleIcon icon1 = new GoogleIcon("green", "http://www.reimers.dk/images/icons/icong.png", "http://www.google.com/mapfiles/shadow50.png", new GoogleSize(20, 34), new GoogleSize(37, 34), new GooglePoint(9, 34), new GooglePoint(0, 0), new GooglePoint(9, 34));

			GoogleIcon icon2 = new GoogleIcon();
			icon2.ID = "black";
			icon2.Image = "http://www.reimers.dk/images/icons/small_black.png";
			icon2.ImageSize = new GoogleSize(12, 20);
			icon2.AnchorPoint = new GooglePoint(6, 20);
			icon2.Shadow = "http://www.reimers.dk/images/icons/small_shadow.png";
			icon2.ShadowSize = new GoogleSize(22, 20);
			icon2.InfoWindowAnchor = icon2.AnchorPoint;

			GoogleLatLng p1 = new GoogleLatLng(38.897312273401731, -77.036733627319336);
			GoogleLatLng p2 = new GoogleLatLng(51.4997134812415, -0.12462615966796875);

			GoogleMarker m1 = new GoogleMarker("m1", p1);
			m1.MarkerText = "&lt;b&gt;White House&lt;/b&gt;&lt;br /&gt;&lt;a href="\&amp;quot;http://www.whitehouse.gov\&amp;quot;" target="\&amp;quot;_blank\&amp;quot;"&gt;Link&lt;/a&gt;";

			GoogleMarker m2 = new GoogleMarker("m2", p2);
			m2.MarkerText = "&lt;b&gt;Westminster&lt;/b&gt;&lt;br /&gt;London, U.K.";
			m2.Options = new GoogleMarkerOptions("Westminster", icon1);
			m1.Options = new GoogleMarkerOptions(icon2);

			GooglePolyline pl = new GooglePolyline();
			pl.Points.Add(p1);
			pl.Points.Add(p2);
			pl.Color = System.Drawing.Color.Crimson;
			pl.Width = 15;
			pl.ID = "pl";
			pl.Opacity = 0.25;

			GMap.Icons.Add(icon1);
			GMap.Icons.Add(icon2);
			GMap.Overlays.Add(m1);
			GMap.Overlays.Add(m2);
			GMap.Overlays.Add(pl);
		}
	}

	protected void GMap_MarkerClick(object sender, OverlayEventArgs e)
	{
		GoogleMarker m = (GoogleMarker)e.Overlay;
		e.MapCommand = m.OpenInfoWindowHTML(e.Map, "&lt;div&gt;" + m.MarkerText + "&lt;/div&gt;");
	}

	protected void GMap_Click(Object sender, CoordinatesEventArgs e)
	{
		e.MapCommand = e.Map.OpenInfoWindowHTML(e.Coordinates, "&lt;div&gt;Lat: " + e.Coordinates.Latitude.ToString() + "&lt;br /&gt;Lng: " + e.Coordinates.Longitude.ToString() + "&lt;/div&gt;");
	}
}
&lt;/pre&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 21:55:05 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/your-first-map</guid></item><item><title>Adding Overlays to Maps</title><link>http://www.reimers.dk:80/tutorials/adding-overlays-to-maps</link><description>&lt;p&gt;The whole point of displaying a map on your page is to present some information. Google's Map API allows you to display two types of overlays: markers and polylines. For the free version these are the two supported overlays. For the licensed version you can create custom overlays that derive from the GoogleOverlay class. However in this tutorial I will focus on markers and polylines. They are to be found in the Reimers.Map namespace.&lt;/p&gt;
&lt;p&gt;A common feature of overlays is that they cannot be defined in the markup. They are created and dealt with in the code behind. The reason behind this is that there are numerous properties that depend on other map objects, fx. icons, and other properties that don't easily get represented using the markup, so I decided to avoid the whole thing all together.&lt;/p&gt;
&lt;p&gt;A common feature for all overlays is that they must have a unique ID, otherwise client-server synchronisation becomes impossible. Be careful when adding overlays to the map's collection. An overlay witht the ID of an existing overlay will push out the old one, as it is presumed it has replaced it. For the same reason overlays should not be added every time the page is posted back to the server. They are kept in the map's viewstate, so there is no reason. Only overlays created using callbacks need to be added to the Overlays collection in a post back.&lt;/p&gt;
&lt;p&gt;The polyline is the least interactive of the overlays. It basically just sits there. You can't fill it or click it and to move it you need to remove it and add a new one. To add a polyline to your map simply create a line object from the GooglePolyline class. The constructor is overloaded to allow for flexibility in creating a GooglePolyline according to your data.&lt;/p&gt;
&lt;p&gt;The following code shows the creation of a GooglePolyline using the most inclusive constructor:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;List&lt;googlelatlng&gt; l = new List&lt;googlelatlng&gt;();
l.Add(new GoogleLatLng(0, 0));
l.Add(new GoogleLatLng(55, -1));
GooglePolyline pl = new GooglePolyline("line", l, System.Drawing.Color.Azure, 5);
GoogleMap1.Overlays.Add(pl);
&lt;/googlelatlng&gt;&lt;/googlelatlng&gt;&lt;/pre&gt;
&lt;p&gt;You will notice that I created the list of GoogleLatLngs before referencing it in the GooglePolyline constructor. You could just add a new generic list of GoogleLatLngs (System.Collections.Generic.List&amp;lt;GoogleLatLng&amp;gt;) and then add the points after. You can add as many points as you want to the polyline, just remember that the data has to be transferred to the client and be handled there. A polyline with hundreds of points can slow down the client considerably. Also notice that the line is added to the map's Overlays collection - in the free version it should be added to the map's Lines collection.&lt;/p&gt;
&lt;p&gt;That's all there is to adding a polyline to your map. If the line doesn't show up check that your page conforms to &lt;a href="http://www.google.com/apis/maps/documentation/#XHTML_and_VML" title="Specifications"&gt;Google's specifications&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To add a marker to your map you follow roughly the same procedure. Markers are more interactive than polylines so I will write some other tutorials about how to change the marker icon, handle marker events and so on. For now we will concentrate on the basic marker. To add a marker simply create a marker object from the GoogleMarker class. Again the constructor is overloaded to simplify marker creation. The simplest way to create a marker is like this:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMarker gm = new GoogleMarker("marker", 55, 0);
GoogleMap1.Overlays.Add(gm);
&lt;/pre&gt;
&lt;p&gt;This will display a marker at the given coordinates with the default icon when the map loads. As with polylines the behavior is different for the free version, where the marker is added to the map's Markers collection.&lt;/p&gt;
&lt;p&gt;That's how you add a marker. Refer to the other tutorials for more information on how to handle marker events and change icons.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 21:45:55 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/adding-overlays-to-maps</guid></item><item><title>Using Custom Icons</title><link>http://www.reimers.dk:80/tutorials/using-custom-icons</link><description>&lt;p&gt;The GoogleMarker uses a default red bubble shaped icon when no custom icon is specified. However if you want something a little more personal or unique you can create your own custom icons. This tutorial shows you how to set up custom icons for your markers. All code samples target the licensed version, but should be usable in the free version too.&lt;/p&gt;
&lt;p&gt;To create a custom icon you will need some graphic files to represent the icon. As a bare minimum you will need one icon image, but preferably also a shadow image. Make sure that the image you use is not copyrighted to anyone else! It is also polite to copy the image to your own server so as not to burden someone elses server.&lt;/p&gt;
&lt;p&gt;When you have the graphic file you can create a custom icon simply by using the GoogleIcon constructors. There is generally no need to change any of the values after the icon creation. The constructors could look like this (for an icon without and with a shadow image respectively):&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleIcon i1 = new GoogleIcon(
"iconNoShadow",
"http://www.reimers.dk/iconimage.png",
new GoogleSize(15, 15),
new GooglePoint(7, 8),
new GooglePoint(7, 8));

GoogleIcon i2 = new GoogleIcon(
	"iconWithShadow",
	"http://www.reimers.dk/iconimage.png",
	"http://www.reimers.dk/shadowimage.png",
	new GoogleSize(15, 15),
	new GoogleSize(20, 15),
	new GooglePoint(7, 8),
	new GooglePoint(0, 8),
	new GooglePoint(7, 8));
&lt;/pre&gt;
&lt;p&gt;Once the icon has been created it must be added to the map's icon collection in the usual way:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMap.Icons.Add(i1);
GoogleMap.Icons.Add(i2);
&lt;/pre&gt;
&lt;p&gt;One thing to note about icons is that they must be added to the map's IconCollection when the page is rendered in order for the icons to be available for use. The icons don't have to be used immediately, but they must be present at render time so that markers added later can reference them. A GoogleMarker can either set the reference to the icon directly in the contructor by setting the GoogleMarkerOptions to the set value or the GoogleMarkerOptions.Icon can be set later, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMarker m = new GoogleMarker("myMarker", 55, 0, new GoogleMarkerOptions(i1));
&lt;/pre&gt;
&lt;p&gt;There is nothing complicated about custom icons. The tricky bit is getting icon images you can use.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 21:36:23 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/using-custom-icons</guid></item><item><title>Creating a Custom Map</title><link>http://www.reimers.dk:80/tutorials/creating-a-custom-map</link><description>&lt;p&gt;Google Maps come with very detailed satellite maps for most of the globe and are expanding their road map coverage almost daily so the need to make your own custom map using your own map graphics may not be necessary. But if you want to show a historical map, a fantasy map, augment Google's map or something else this tutorial is for you. I will go through the steps of making a custom map. The tutorial will be in two parts, the first will focus on setting up your map page, while the second will show you how to set up your tile server. I will write a seperate tutorial on how to display WMS maps.&lt;/p&gt;
&lt;p&gt;Before you begin to set up your custom make sure you are entitled to use the images you are publishing.&lt;/p&gt;
&lt;p&gt;A normal map holds the three built-in map types from Google, normal map, satellite map and hybrid map. These are represented by the GoogleNormalMap, GoogleSatelliteMap and GoogleHybridMap, respectively.&lt;/p&gt;
&lt;p&gt;A custom map is essentially a holder for the different tile layers that make up the map. The first two of the above map types has only one tile layer each and in the Google Maps .NET Control these tile layers are represented by the built-in NormalMapTileLayer and SatelliteTileLayer. The hybrid map consists of two tile layers, the SatelliteTileLayer and the built-in StreetMapTileLayer. These tile layers can be combined with custom tile layers created from the CustomTileLayer class into a custom map from the CustomMapType class.&lt;/p&gt;
&lt;p&gt;To create a custom tile layer you can use either a tile layer from the WMSTileLayer class (covered in another tutorial) or the GoogleTileLayer class. In this tutorial we will use a pre-defined tile layer (NormalMapTileLayer) and create our own using the GoogleTileLayer class. The GoogleTileLayer class uses Google style map tiles, but can be modified easily. At minimum you will need to provide an ID and a URL for the map tile server. You can also restrict the available zoom levels and it is a good idea to set the IsPng property to true if you are using .png files for your tiles (the default is false, setting it to true displays the png files properly in Internet Explorer).&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;NormalMapTileLayer ntl = new NormalMapTileLayer("ntl");

GoogleTileLayer gtl = new GoogleTileLayer();
gtl.ID = "gtl";
gtl.IsPng = true;
gtl.MinZoomLevel = 0;
gtl.MaxZoomLevel = 17;
gtl.Version1ZoomOrder = false;
gtl.BaseUrls.Add("http://www.reimers.dk/demos/mapbase2.aspx?");
&lt;/pre&gt;
&lt;p&gt;As you can see the predefined tile layer requires no further ado. The GoogleTileLayer properties are easy to set and that is all that is required to create your custom tile layer.&lt;/p&gt;
&lt;p&gt;Next step is to create your custom map type using the CustomMapType class. To make it work you will need to give it a unique ID and set some name to display in the map type control (unless you don't use the map type control). Apart from that all you need to do is to add the tile layers you want to use for the custom map. Watch out that you add them in the right order. The tile layers are ordered according to the index number in the custom map's Layers collection, i.e. index 0 is under index 1 etc. To create a custom map using the above tile layers with the normal map below we could use the following code:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;CustomMapType cmt = new CustomMapType();

cmt.ID = "cmt";
cmt.Name = "XML Demo";
cmt.Layers.Add(ntl);
cmt.Layers.Add(gtl);
&lt;/pre&gt;
&lt;p&gt;Now that we have our custom map we need to tell the control to render it. By default the control displays the three default map types, but this can be modified by altering the MapTypes collection in the map options. For the purposes of this demo we will simply show the custom map and so will clear the other maps and add our custom map, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMap1.Options.MapTypes.Clear();
GoogleMap1.Options.MapTypes.Add(cmt);
&lt;/pre&gt;
&lt;p&gt;This is almost it. Now we need to set up the page that serves the map tiles. To do this we need to create a file (either an .aspx page, but probably more suitably an .ashx handler) that reads the tile request and returns the right tile file. This is done by reading the x, y and zoom values in the request's querystring and then finding the corresponding file. The response stream is cleared&amp;nbsp; and the file is sent in its place as if the file itself had been requested, like so:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	string x = Request.QueryString["x"];
	string y = Request.QueryString["y"];
	string z = Request.QueryString["zoom"];
	string mapfile = String.Format("/demos/x{0}y{1}z{2}.png", x, y, z);

	if (!System.IO.File.Exists(Server.MapPath(mapfile)))
	{
		mapfile = "/demos/black.png";
	}

	Response.Clear();
	Response.ContentType = "image/png";
	Response.WriteFile(Server.MapPath(mapfile));
	Response.End();
}
&lt;/pre&gt;
&lt;p&gt;Once these steps have been taken you should have your custom map up and running.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 21:31:55 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/creating-a-custom-map</guid></item><item><title>Understanding Async Events</title><link>http://www.reimers.dk:80/tutorials/understanding-async-events</link><description>&lt;p&gt;I frequently get asked why the following code yields no result:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMarker gm = new GoogleMarker("myMarker", 54, 0);
GoogleMap.AddOverlay(gm);
&lt;/pre&gt;
&lt;p&gt;It's actually the same as asking why the following code produces no result:&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;"Hello World";&lt;/pre&gt;
&lt;p&gt;Many of the methods in the GoogleMap class and also in the GoogleMarker class return a JavaScript command to handle the underlying Google API. I have named these methods according to the underlying API method that they shadow. Obviously this can cause some confusion, even though I attempted to avoid confusion by using similar naming. Just shows that you can't win.&lt;/p&gt;
&lt;p&gt;So hopefully to clarify this here's an explanation of how to make use of the Google Maps .NET Control and know the difference between methods that generate JavaScript and methods that handle serverside objects.&lt;/p&gt;
&lt;p&gt;All the methods that return a string value and where the &lt;a href="http://www.reimers.dk/documentation/default.aspx"&gt;documentation&lt;/a&gt; states that they return a JavaScript command are intended as helper methods for programmers who don't want to write JavaScript commands themselves. Since the control requires a multitude of JavaScript commands to be executed on the client to get full advantage of the clientside and AJAX functionality of a map application you must pass these JavaScript commands as the browser will not understand .NET commands.&lt;/p&gt;
&lt;p&gt;Most frequently the JavaScript commands are used to send to the MapCommand string in a serverside event handler. But they can just as well be used to generate JavaScript to send to the clientside handlers. Finally the PostRenderScript is a property that accepts JavaScript to be executed after the map has finished rendering, which is another place where the helper methods can be useful.&lt;/p&gt;
&lt;p&gt;In all of the above cases a programmer can just as well write his own custom JavaScript, which may sometimes be needed if the included scripts are not enough. For example for my &lt;a href="http://www.reimers.dk/atlas/map.aspx" style="color: #000000;"&gt;map page&lt;/a&gt; I had to write a fair amount of code to integrate Google's AJAX search API and the Wikipedia search function. Obviously these integrations fall outside a basic map application and so they needed to be created specially for this application. After all there are only so many possibilities I can foresee. To help programmers integrate clientside scripting ASP.NET has the ClientscriptManager class which helps you integrate clientside scripting from the code behind.&lt;/p&gt;
&lt;p&gt;The properties of the control are properties in the conventional .NET way. They are used to set values on the server. Many of them perform similar functions to the methods above. They are intended to help programmers set up the map before rendering the page.&lt;/p&gt;
&lt;p&gt;In fact the map can be run in a "traditional" ASP.NET way i.e. every click sends the page to the server whch handles events and returns a new page. To do this, simply have every eventhandler submit the page to the server and handle the event on the server. However I suspect that soon your visitors will start complaining.&lt;/p&gt;
&lt;p&gt;The following code shows two different ways to add a marker to a map. The first code snippet shows how to create a marker on the server and then add it to the map's OverlayCollection. The collection will remember the marker through postbacks and display the marker when the page is loaded.&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
	GoogleMarker gm = new GoogleMarker("myMarker", 51, 0);
	GoogleMap.Overlays.Add(gm);
}
&lt;/pre&gt;
&lt;p&gt;This second code sample shows how a marker is created on the server and sent to the client to be rendered using a callback (by using an event handler in this case). The marker gets plotted on the map but is not added to the map's OverlayCollection and so is forgotten upon postback, unless the information is saved somewhere else.&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void MapClick(GoogleMap Map, GoogleLatLng Position, ref string MapCommand)
{
	GoogleMarker gm = new GoogleMarker("myMarker", 51, 0);
	MapCommand = GoogleMap.AddOverlay(gm);
}
&lt;/pre&gt;
&lt;p&gt;So as can be seen from the above programming clientside code is slightly more cryptic than the more straightforward serverside coding. Clientside coding however is what makes a great AJAX application so some thought will have to be put into how to keep clientside and serverside object coordinated between and through postbacks.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 21:26:50 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/understanding-async-events</guid></item><item><title>Reading Overlay Data From a Database</title><link>http://www.reimers.dk:80/tutorials/reading-overlay-data-from-a-database</link><description>&lt;p&gt;It is safe to say that most map applications are based on data stored in databases. I can't begin to guess how people design their databases, but getting the data on to the map is generally speaking a question of drawing out the desired result set and looping through it creating the relevant overlays in the process. There is nothing difficult about this and it mirrors pulling data out of a database for many other purposes.&lt;/p&gt;
&lt;p&gt;I should add here that there is no databinding feature in the Google Maps .NET Control. The reason is that overlays can be created in so many different ways with so many different options that it becomes unwieldly to do this in a generalized manner.&lt;/p&gt;
&lt;p&gt;Most people will choose to use the SqlDataReader (or depending on your database the MySqlDataReader, OleDbDataReader or OdbcDataReader) class to read their data back from the database as it is the fastest way to read data that you need as read-only. In short something like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;//Set up the database connection.
System.Data.SqlClient.SqlConnection conn =
	new System.Data.SqlClient.SqlConnection("Your connection string");

System.Data.SqlClient.SqlCommand cmd =
	new System.Data.SqlClient.SqlCommand("SELECT ID, Lat, Lng, Text FROM Overlays", conn);

conn.Open();
System.Data.SqlClient.SqlDataReader dtr = cmd.ExecuteReader();

while (dtr.Read())
{
	//Create your overlays.
	GoogleMarker marker = new GoogleMarker();
	marker.ID = (string)dtr["ID"];
	marker.Latitude = (double)dtr["Lat"];
	marker.Longitude = (double)dtr["Lng"];
	marker.MarkerText = (string)dtr["Text"];
	GoogleMap.Overlays.Add(marker);
}

conn.Close();
&lt;/pre&gt;
&lt;p&gt;The above code doesn't do much processing and should be fairly fast. But if you are going to do a little more processing of your data to create the overlays then you quickly end up keeping your database connection open longer than is necessary. It is not difficult to think of an example where you analyze the data before determining how to create the overlay, e.g. if the latitudes and longitudes are an array you create a polyline, if not create a marker. Or, as in the example below you want to plot only points inside a defined polygon.&lt;/p&gt;
&lt;p&gt;Either your could write a long SQL query which does it own calculation or you can leave that to the Contains() method of the GooglePolygon class. This way you can limit your SQL query to drawing out those rows where the latitude and longitude are within the bounds of the polygon and then leave it up to a final determination up to the Contains() method. This way your code would look something like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;//Dummy polygon for the sake of example.
GooglePolygon polygon = new GooglePolygon();

//Set up the database connection.
System.Data.SqlClient.SqlConnection conn =
	new System.Data.SqlClient.SqlConnection("Your connection string");

System.Data.SqlClient.SqlCommand cmd =
	new System.Data.SqlClient.SqlCommand(
	@"SELECT ID, Lat, Lng, Text FROM Overlays WHERE Lat &amp;lt; @MaxLat AND Lat &amp;gt; @MinLat AND Lng &amp;lt; @MaxLng AND Lng &amp;gt; @MinLng",
	conn);

cmd.Parameters.AddWithValue("@MaxLat", polygon.Bounds.MaxLatitude);
cmd.Parameters.AddWithValue("@MinLat", polygon.Bounds.MinLatitude);
cmd.Parameters.AddWithValue("@MaxLng", polygon.Bounds.MaxLongitude);
cmd.Parameters.AddWithValue("@MinLng", polygon.Bounds.MinLongitude);
conn.Open();
System.Data.SqlClient.SqlDataReader dtr = cmd.ExecuteReader();

while (dtr.Read())
{
	if (polygon.Contains(new GoogleLatLng((double)dtr["Lat"], (double)dtr["Lng"])))
	{
		//Create your overlays.
		GoogleMarker marker = new GoogleMarker();
		marker.ID = (string)dtr["ID"];
		marker.Latitude = (double)dtr["Lat"];
		marker.Longitude = (double)dtr["Lng"];
		marker.MarkerText = (string)dtr["Text"];
		GoogleMap.Overlays.Add(marker);
	}
}
conn.Close();
&lt;/pre&gt;
&lt;p&gt;This code is obviously not very high quality as it will keep the database connection open much longer than is necessary. But it serves as an example of how processing of data can be done while it is being read from the database.&lt;/p&gt;
&lt;p&gt;The above is a very good example of when the SqlDataReader is not necessarily the best thing to use from an overall point of view. Here I think it makes sense to read the data into a DataTable, close the database connection and then go on processing the data. When filling DataTables most people would opt for the SqlDataAdapter to do the work. Personally I like to use the SqlDataReader to create a strongly typed DataTable and then fill it, like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;System.Data.SqlClient.SqlDataReader dtr = cmd.ExecuteReader();
for (int i = 0; i &amp;lt; dtr.FieldCount; i++) dt.Columns.Add(dtr.GetName(i), dtr.GetFieldType(i));
while (dtr.Read())
{
	DataRow dr = dt.NewRow();
	for (int i = 0; i &amp;lt; dtr.FieldCount; i++) dr[i] = dtr[i];
	dt.Rows.Add(dr);
}
&lt;/pre&gt;
&lt;p&gt;But that choice is up to you. If you are using data from several tables and intend to update the information later on you might as well not bother with the SqlDataAdapter as it is not capable of generating scripts that deal with multiple tables.&lt;/p&gt;
&lt;p&gt;After you have filled your DataTable and closed your database connection you can loop through the data and create your overlays. The following code shows how to quickly grab the data from the database after a cursory selection, close the connection as quickly as possible and then analyze the data for the final selection.&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;DataTable dt = new DataTable();
//Dummy polygon for the sake of example.

GooglePolygon polygon = new GooglePolygon();
//Set up the database connection.

System.Data.SqlClient.SqlConnection conn =
    new System.Data.SqlClient.SqlConnection("Your connection string");

System.Data.SqlClient.SqlCommand cmd =
    new System.Data.SqlClient.SqlCommand(
    @"SELECT ID, Lat, Lng, Text FROM Overlays 
    WHERE Lat &amp;lt; @MaxLat AND Lat &amp;gt; @MinLat AND Lng &amp;lt; @MaxLng AND Lng &amp;gt; @MinLng", 
conn);

cmd.Parameters.AddWithValue("@MaxLat", polygon.Bounds.MaxLatitude);
cmd.Parameters.AddWithValue("@MinLat", polygon.Bounds.MinLatitude);
cmd.Parameters.AddWithValue("@MaxLng", polygon.Bounds.MaxLongitude);
cmd.Parameters.AddWithValue("@MinLng", polygon.Bounds.MinLongitude);
conn.Open();

SqlDataReader dtr = cmd.ExecuteReader();

for (int i = 0; i &amp;lt; dtr.FieldCount; i++) dt.Columns.Add(
    dtr.GetName(i), dtr.GetFieldType(i));

while (dtr.Read())
{
    DataRow dr = dt.NewRow();
    for (int i = 0; i &amp;lt; dtr.FieldCount; i++) dr[i] = dtr[i];
    dt.Rows.Add(dr);
}
dtr.Close();
conn.Close();

for (int i = 0; i &amp;lt; dt.Rows.Count; i++)
{
    DataRow dr = dt.Rows[i];

    if (polygon.Contains((double)dr["Lat"], (double)dr["Lng"]))
    {
        GoogleMarker marker = new GoogleMarker();
        marker.ID = (string)dr["ID"];
        marker.Latitude = (double)dr["Lat"];
        marker.Longitude = (double)dr["Lng"];
        marker.MarkerText = (string)dr["Text"];
        GoogleMap.Overlays.Add(marker);
    }
}
&lt;/pre&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 20:26:47 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/reading-overlay-data-from-a-database</guid></item><item><title>Dealing With Obscene Amounts of Markers</title><link>http://www.reimers.dk:80/tutorials/dealing-with-obscene-amounts-of-markers</link><description>&lt;p&gt;Dealing with obscene amounts of overlays (typically markers or extremely long and complex polylines) is not recommendable. Most importantly Google's underlying API becomes terribly slow when dealing with more than 200 markers and complex polylines can create odd effects when scrolling the map. But equally important is the impression for the reader. Who can actually absorb the information that lies in 1000 plotted markers?&lt;/p&gt;
&lt;p&gt;One of the reasons behind the success of Google's search engine is its ability to present the desired search results at the top of the result list. They are very aware that users don't go through 1000 results and compare and research. In the same way I think it is safe to say it is highly unlikely that users are going to read and/or understand the information hidden behind 1000 markers. This doesn't really supply any useful information.&lt;/p&gt;
&lt;p&gt;OK, this is a somewhat artificial example as you may not always be in charge of which search results are returned to the user. But you can be in charge of grouping the returned search results into something useful. Consider for example a real estate site that want to show houses in a certain price range. This would naturally be grouped by town or zip code. To present a friendlier result than throwing all the offers at the user at the same time or obliging him to perform multiple searches the results could be bound to "master markers" representing each zip code.&lt;/p&gt;
&lt;p&gt;Google's API has the MarkerManager class which is not implemented in the Google Maps .NET Control. Instead the control has several functions to help with serverside marker management. After all there is a reason that developers have decided not to throw themselves directly into the clientside API. Also, when using serverside overlay management one can interact with a supporting database instead of reading all the overlays at page load.&lt;/p&gt;
&lt;p&gt;Let's have a look at a generic example of how to create a map that first gets the relevant zip codes, plots them and uses them to fetch markers for that area when clicked.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;Note, this example is not going to work for the free version as it lacks many of the database integration and collection search functions that the example relies on.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;First we have to plot all the zip codes that are relevant to the search. To this end we need an icon to distinguish the zip code markers from the house markers. Afterwards the zip code results get plotted with the zip code icon. The following code shows how a page load event can look like:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;protected void Page_Load(object sender, EventArgs e)
{
    //Create a zip code icon and a house icon.

    if (!Page.IsPostBack)
    {
        GoogleIcon zipicon = new GoogleIcon(
            "zip",
            "http://www.yourdomain.com/images/zip.png",
            new GoogleSize(20, 20),
            new GooglePoint(10, 10),
            new GooglePoint(10, 10));

        GoogleMap.Icons.Add(zipicon);
        GoogleIcon houseicon = new GoogleIcon(
            "house",
            "http://www.yourdomain.com/images/house.png",
            new GoogleSize(20, 20),
            new GooglePoint(10, 10),
            new GooglePoint(10, 10));

        GoogleMap.Icons.Add(houseicon);

        //Get all relevant zip codes.
        //In this example I presume that you have a view in your database that joins two tables.
        //One table holds the real estate listings and the other holds zip codes and their locations.
        //The two tables are joined by the zipcode field.

        string qryZip = @"SELECT DISTINCT zipcode, ziplatlng FROM vue_RealEstateZip WHERE price BETWEEN @minprice AND @maxprice";

        SqlCommand cmd = new SqlCommand(qryZip, conn);
        cmd.Parameters.AddWithValue("@minprice", 100);
        cmd.Parameters.AddWithValue("@maxprice", 200);
        conn.Open();
        SqlDataReader dtr = cmd.ExecuteReader();

        while (dtr.Read())
        {
            GoogleMarker zipmarker = new GoogleMarker();
            zipmarker.ID = (string)dtr["zipcode"];
            zipmarker.Point = GoogleLatLng.FromSqlLatLng(dtr["ziplatlng"]);
            //If not using the SqlLatLng UDT you may have to create the GoogleLatLng from other columns.
            zipmarker.Options.Icon = GoogleMap.Icons[0];

            //If we don't know the index position of the icon to use we can use the Find method
            //zipmarker.Options.Icon = GoogleMap.Icons.Find(
            //  delegate(GoogleIcon icon)
            //    {
            //        if (icon.ID == "zip") return true;
            //        return false;
            //    }
            //    );

            zipmarker.Options.Title = (string)dtr["zipcode"];
            //Finally we need to make the map react to clicks on the zip code markers.
            zipmarker.ClientSideHandlers.OnClick =
                GoogleMap.CreateMapCallback((string)dtr["zipcode"], false);
            GoogleMap.Overlays.Add(zipmarker);
        }

        dtr.Close();
        conn.Close();
    }
}
&lt;/pre&gt;
&lt;p&gt;The next thing to do is to react to clicks on zip code markers. In the example above we did not use the conventional OverlayClick event to handle clicks on zip code markers. Instead each marker got a clientside handler that initiates a callback to the ExternalCallback event with the zip code as the argument. So it is in this event that we need to get the zip code and plot the corresponding markers.&lt;/p&gt;
&lt;p&gt;First of all remember to register the event handler out the if(!Page.IsPostback) block like so:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMap.ExternalCallback +=
	new ExternalCallbackHandler(GoogleMap_ExternalCallback);
&lt;/pre&gt;
&lt;p&gt;Then comes the actual event handler. In the event handler any existing house markers are removed first. Then the zip code argument is used to search the database and the returned markers are plotted.&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;void GoogleMap_ExternalCallback(string Argument, ref string MapCommand)
{
	//First remove all markers that use the house icon (house markers)

	foreach (GoogleOverlay ov in GoogleMap.Overlays.FindAll(
		delegate(GoogleOverlay overlay)
		{
			if (overlay is GoogleMarker &amp;amp;&amp;amp; ((GoogleMarker)overlay).Options.Icon.ID == "house") return true;
			return false;
		}))
	{
		MapCommand += GoogleMap.RemoveOverlay(ov, true);
	}

	//Next search the database for housing matches in the given zip code.

	string qryHouse = @"SELECT ID, position, description FROM tbl_RealEstate WHERE (zip = @zip) AND (price BETWEEN @minprice AND @maxprice)";

	SqlCommand cmd = new SqlCommand(qryHouse, conn);
	cmd.Parameters.AddWithValue("@minprice", 100);
	cmd.Parameters.AddWithValue("@maxprice", 200);
	cmd.Parameters.AddWithValue("@zip", Argument);
	conn.Open();
	SqlDataReader dtr = cmd.ExecuteReader();

	while (dtr.Read())
	{
		GoogleMarker house = new GoogleMarker();
		house.ID = (string)dtr["ID"];
		house.Point = GoogleLatLng.FromSqlLatLng(dtr["position"]);
		house.ClientSideHandlers.OnClick =
			house.OpenInfoWindowHTML(
			GoogleMap,
			(string)dtr["description"]);

		MapCommand += GoogleMap.AddOverlay(house, true);
	}

	dtr.Close();
	conn.Close();
}
&lt;/pre&gt;
&lt;p&gt;The above example depends very much on database searching. Theoretically all the markers could be loaded into the overlay collection on the initial load and then RenderSelected property could be passed a Predicate that made the map only display markers using the zipicon, something like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleMap.Overlays.RenderSelected =
	delegate(GoogleOverlay overlay)
	{
		if (overlay is GoogleMarker &amp;amp;&amp;amp; ((GoogleMarker)overlay).Options.Icon.ID == "zip") return true;
		return false;
	};
&lt;/pre&gt;
&lt;p&gt;But this approach would in all likelyhood lead to an enormous amount of data being moved to and from the client because all the marker data that is not displayed is still stored by the control state management. So if you are going to preload an obscene amount of markers (&amp;gt;500) then make sure you test the user experience first.&lt;/p&gt;
&lt;p&gt;As written in the beginning the Google Maps .NET Control does not includes support for the clientside MarkerManager, but from version 3.4 it has many methods to search collections and generate specialized callbacks, which allows very detailed overlays handling using serverside code. Combined with callbacks this should provide a flexible and responsive user experience.&lt;/p&gt;
&lt;p&gt;If you are going to be presenting very complex polylines then I suggest writing them as KML files (can also be done dynamically through the control) and presenting them through a KmlTileLayer. The KmlTileLayer leaves it up to Google to crunch through the data and return it as images.&lt;/p&gt;
&lt;p&gt;As with all kinds of data one should be aware of information overload. Flooding the user with data is going to overwhelm them and in the end be as uninformative as too little data.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 20:16:38 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/dealing-with-obscene-amounts-of-markers</guid></item><item><title>Creating a Static Map</title><link>http://www.reimers.dk:80/tutorials/creating-a-static-map</link><description>&lt;p&gt;The map control includes support for &lt;a href="http://code.google.com/apis/maps/documentation/staticmaps/" title="Google Static Maps API" style="color: #000000;"&gt;Google's Static Maps API&lt;/a&gt;. The Static Maps API allows you to create a map as an image. This significantly reduces the download required for users viewing a web page. The static map is ideal in situations where you need a map to show location, but do not require any user interaction. If you want to display a map on a mobile page then this is ideal.&lt;/p&gt;
&lt;p&gt;Static maps support markers and polylines, so you can add basic guidance. Markers and lines are not clickable, so you cannot mimic user interaction this, but the map image itself can be made clickable.&lt;/p&gt;
&lt;p&gt;The following markup shows how to put a basic map on a webpage.&lt;/p&gt;
&lt;p&gt;HTML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Reimers:GoogleStaticMap runat="server"
AlternateText="Static Map"
Center="55.6833,12.5833" 
DisplayLanguage="Danish" 
Height="512" 
Width="512" 
ID="sMap" 
Zoom="14" 
ImageFormat="Png" 
GoogleKey="YourGoogleKey" /&amp;gt;
&lt;/pre&gt;
&lt;p&gt;If you want to add overlays you can do so in the code behind. While static overlays (GoogleStaticOverlay) are not directly interchangeable with normal GoogleOverlay (they will be soon), they are added in much the same way:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;GoogleStaticMarker m1 = new GoogleStaticMarker("a", sMap.Center, Color.Blue, 'J', GoogleStaticMarkerSize.Mid);
sMap.Overlays.Add(m1);

GoogleStaticPolyline line = new GoogleStaticPolyline();
line.ID = "l1";
line.Opacity = 0.5f;
line.LineColor = Color.Red;
line.Width = 5;
line.Points.Add(sMap.Center);
line.Points.Add(new Reimers.Map.GoogleLatLng(55.7, 12.6));
sMap.Overlays.Add(line);
&lt;/pre&gt;
&lt;p&gt;The classes necessary to create static maps are located in the Reimers.Map.Static namespace.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 20:03:46 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/creating-a-static-map</guid></item><item><title>Creating Your Own Overlay Types</title><link>http://www.reimers.dk:80/tutorials/creating-your-own-overlay-types</link><description>&lt;p&gt;I previously wrote a post about how to create a custom map type. It does require a slight knowledge of JavaScript, since you will be accessing the underlying API or custom clientside scripts.&lt;/p&gt;
&lt;p&gt;Since the request was in relation to a custom overlay type called &lt;a href="http://googlemapsapi.blogspot.com/2007_04_01_googlemapsapi_archive.html" title="LabeledMarker" target="_blank"&gt;LabeledMarker&lt;/a&gt;, I decided to write this post based on that. However at the bottom I will go through how you can create an overlay derived from the GoogleOverlay class. Be aware that the code presented here is not guaranteed to work, please report any errors you may experience.&lt;/p&gt;
&lt;p&gt;The first thing to do if you want to do if you are using libraries outside the code Google Maps API is to ensure that the library is loaded on your page. There are several ways to do this, either manually include the script tag on your page (remember to put it either in the head or at the top of the page, so it is available when the map script runs), or programatically by using either the ClientScriptManager or the ScriptManager. Of course it goes without saying that you should not hot link to the &lt;a href="http://gmaps-utility-library.googlecode.com/svn/trunk/labeledmarker/release/src/labeledmarker.js" title="LabeledMarker Library" target="_blank"&gt;LabeledMarker library&lt;/a&gt; :-)&lt;/p&gt;
&lt;p&gt;Creating the Overlay&lt;/p&gt;
&lt;p&gt;In the &lt;a href="http://gmaps-utility-library.googlecode.com/svn/trunk/labeledmarker/release/src/labeledmarker.js" title="LabeledMarker Library" target="_blank"&gt;JavaScript library&lt;/a&gt; you can see that the LabeledMarker itself is derived from the GMarker, so it makes sense to start our implementation by creating a class that inherits from the GoogleMarker class (the .NET equivalent). This means that we don't have to write a lot of code to add all the functionality of a marker. The main difference is that the LabeledMarker takes a LabelText value in the constructor. In principle we could grab that value from the GoogleMarker's MarkerText property, but I decided to add an extra property (LabelText) for the purposes of this tutorial. The icon value already exists for the GoogleMarker, so we will continue to use that.&lt;/p&gt;
&lt;p&gt;The LabelText property is like any other .NET property, but note that for state preservation purposes you will need to write your own override for the XML serialization, so that the value is not lost between page roundtrips.&lt;/p&gt;
&lt;p&gt;Finally we come to the tricky part, which is writing the code that will generate the JavaScript which renders the control on the page.&amp;nbsp; The JavaScript declaration looks like this:&lt;/p&gt;
&lt;p&gt;JavaScript&lt;/p&gt;
&lt;pre class="brush: js;"&gt;var marker = new LabeledMarker(myPoint, {icon: myIcon, labelText: "A"});&lt;/pre&gt;
&lt;p&gt;So the RenderString method must output at least this code. However the map control needs a little extra information to keep track of the overlays, so we need to add some more code to add an ID property to the clientside overlay. The overridden RenderString method will look something like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;public override string RenderString(GoogleMap Map)
{
	return string.Format("var {0} = new LabelMarker(new {1}, {{ \"icon\" : reimers.map.{2}.getIcon(\"{3}\"), \"labelText\" : \"{4}\" }}); {0}.ID = \"{0}\"; ",
		ClientSideID(Map),
		Point.ToString(),
		Map.ID,
		Options.Icon.IconMapID,
		LabelText);
}
&lt;/pre&gt;
&lt;p&gt;As you can see output is basically the same as the JavaScript snippet above, but there are a few things to notice. After the clientside LabeledMarker is instantiated an ID property is added, which is the same as the variable name. This is in order to maintain varaible references. The actual variable name is generated by the ClientSideID method, so you don't need to worry too much about about the naming that of variables.&lt;/p&gt;
&lt;p&gt;The JavaScript for the marker point is taken from the GoogleLatLng class, but 'new' is prepended, since it is not know by teh client.&lt;/p&gt;
&lt;p&gt;The icon is found using the reimers.map.[MapID].getIcon clientside function. The icons that you create on the server are stored and referenced on the client by the control, but you can access the icon collection yourself using this function. Yes there is an equivalent getOverlay function.&lt;/p&gt;
&lt;p&gt;The LabelText property is added to the output. Note that in the property accessor I manually escape double quotes, so that you don't run into trouble with unwanted string terminations.&lt;/p&gt;
&lt;p&gt;This is basically it. A sample class code could look like this:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;using System;

namespace Reimers.Map.Extensions
{
    public class LabeledMarker : GoogleMarker
    {
        private string lText = string.Empty;

        public string LabelText
        {
            get { return lText.Replace("\"", "\\\""); }
            set { lText = value; }
        }

        public override string RenderString(GoogleMap Map)
        {
            return string.Format("var {0} = new LabelMarker(new {1}, {{ \"icon\" : reimers.map.{2}.getIcon(\"{3}\"), \"labelText\" : \"{4}\" }}); {0}.ID = \"{0}\"; ",
                ClientSideID(Map),
                Point.ToString(),
                Map.ID,
                Options.Icon.IconMapID,
                LabelText);
        }

        public override void ReadXml(System.Xml.XmlReader reader)
        {
            //This should be overridden to ensure that the label text
            //is preserved by the state management.
            base.ReadXml(reader);
        }

        public override void WriteXml(System.Xml.XmlWriter writer)
        {
            //This should be overridden to ensure that the label text
            //is preserved by the state management.
            base.WriteXml(writer);
        }
    }
}
&lt;/pre&gt;
&lt;p&gt;If you are more courageous and want to create your overlay from scratch, i.e. an overlay that derives directly from the GOverlay class then you must write an equivalent .NET class that inherits from the GoogleOverlay class.&lt;/p&gt;
&lt;p&gt;The GoogleOverlay class has a number of abstract methods that you need to handle. There are the ones described above. The XML serialization is self-explanatory and the RenderString should output the JavaScript code necessary to render the control.&lt;/p&gt;
&lt;p&gt;When inheriting directly from the GoogleOverlay class you must also override the ClientSideID method, which is the method that generates the ID used clientside to reference the overlay. You need to ensure that the variable does not use characters that have special meaning in JavaScript.&lt;/p&gt;
&lt;p&gt;Happy customization.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 19:59:55 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/creating-your-own-overlay-types</guid></item><item><title>ExternalCallback Example</title><link>http://www.reimers.dk:80/tutorials/externalcallback-example</link><description>&lt;p&gt;The GoogleMap class includes the ExternalCallback event, which is intended as an alternative way to pass map related data to be processed on the server using callbacks. I'm not going to go into the details of callbacks, except to say that it is similar to UpdatePanels. There is one very important difference. If you want the browser page to do anything you have to pass back a JavaScript command which will be run. The control has a load of helper methods which help you create these commands. But remember, you cannot work directly with your server controls. Even though you can read their values, any changes will not be passed back to the browser page.&lt;/p&gt;
&lt;p&gt;The GoogleMap class also includes a helper method called CreateMapCallback, which will generate the necessary JavaScript to allow you to use the external callback feature. Since it is standard JavaScript, it can be applied to any DOM event or any JavaScript function.&lt;/p&gt;
&lt;p&gt;In the example below the external callback is attached to the click event of a button, but as said it could just as well have been attached to a mouseover event of some element. When the button is clicked then the argument is passed back to the server, where it is handled. Callbacks have an important limitation, you can only pass back strings. However this is not such a big limitation. You can have the server check what argument is passed and react appropriately.&lt;/p&gt;
&lt;p&gt;Before we go on, here's the example code.&lt;/p&gt;
&lt;p&gt;The markup&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;%@ Page Language="C#" AutoEventWireup="true" CodeFile="externalcallback.aspx.cs" Inherits="examples_csharp_externalcallback" %&amp;gt;

&amp;lt;%@ Register Assembly="GoogleMap" Namespace="Reimers.Map" TagPrefix="Reimers" %&amp;gt;
&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
&amp;lt;head id="Head1" runat="server"&amp;gt;
	&amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
	&amp;lt;form id="form1" runat="server"&amp;gt;
	&amp;lt;div&amp;gt;
		&amp;lt;Reimers:GoogleMap runat="server" ID="googleMap" /&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div&amp;gt;
		&amp;lt;asp:Button UseSubmitBehavior="false" runat="server" ID="btnA" Text="Button A" /&amp;gt;
		&amp;lt;asp:Button UseSubmitBehavior="false" runat="server" ID="btnB" Text="Button B" /&amp;gt;
		&amp;lt;asp:Button UseSubmitBehavior="false" runat="server" ID="btnC" Text="Button C" /&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;/form&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The code behind&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;using System;
using Reimers.Map;

public partial class examples_csharp_externalcallback : System.Web.UI.Page
{
	protected override void OnInit(EventArgs e)
	{
		base.OnInit(e);

		googleMap.ExternalCallback += new Reimers.Map.ExternalCallbackHandler(googleMap_ExternalCallback);
	}

	protected override void OnLoad(EventArgs e)
	{
		base.OnLoad(e);

		btnA.OnClientClick = googleMap.CreateMapCallback("A", false) + "return false;";
		btnB.OnClientClick = googleMap.CreateMapCallback("B", false) + "return false;";
		btnC.OnClientClick = googleMap.CreateMapCallback("C", false) + "return false;";
	}

	void googleMap_ExternalCallback(string Argument, ref string MapCommand)
	{
		MapCommand = googleMap.ClearOverlays();
		GoogleMarker mrk = new GoogleMarker("mrk");

		switch (Argument)
		{
			case "A":
				mrk.Point = new GoogleLatLng(51.47, 0.0);
				mrk.Options.Title = "Marker A";
				break;
			case "B":
				mrk.Point = new GoogleLatLng(48.85, 2.4);
				mrk.Options.Title = "Marker B";
				break;
			case "C":
				mrk.Point = new GoogleLatLng(0.0, 0.0);
				mrk.Options.Title = "Marker C";
				break;
			default:
				break;
		}

		MapCommand += googleMap.AddOverlay(mrk);//Not persisted to map state, i.e. lost on postback
		//MapCommand += googleMap.AddOverlay(mrk, true); //Persisted to map state, i.e. remembered through postbacks
	}
}

&lt;/pre&gt;
&lt;p&gt;When you look at the handler for the ExternalCallback first creates a command that clears all overlays from the map. Afterwards it creates a marker depending on which button was clicked. The command to add this is then added to the MapCommand so it will be passed back to the browser. It's that simple.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 19:49:34 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/externalcallback-example</guid></item><item><title>Clustering Overlays in Silverlight</title><link>http://www.reimers.dk:80/tutorials/clustering-overlays-in-silverlight</link><description>&lt;p&gt;One of the cool things about map applications in Silverlight is that they don't have the same limits on the amount of overlays it can display as HTML based maps have. This means that you can easily display 1000+ overlays without any noticeable degradation in performance. But just because your Silverlight map can handle it doesn't mean that your users can maintain their overview if you flood them with markers. This is where clustering comes. A cluster allows you to display a marker to represent a bunch of others, and when the cluster marker is clicked the contained markers are displayed.&lt;/p&gt;
&lt;p&gt;The OverlayManager now supports displaying overlays in clusters. The OverlayManager's Clustering property takes an ICluster interface. The ICluster interface defines the values needed for the OverlayManager to cluster overlays in the collection. As long as your class implements the ICluster interface you can now define your clustering rule to fit your own application. The strength of the Silverlight UI engine and the flexibility gained from attached properties mean that you have total control of your clustering. However with total control come the problems of implementation.&lt;/p&gt;
&lt;p&gt;The Reimers.Silverlight assembly comes with one clustering rule defined, the BoundsClustering class. This class one way of clustering overlays that made sense to me. Use it if it makes sense to you, or use it as an example for your own clustering. The clustering is defined as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It receives a collection of overlays and figures out what the bounding box of the collection is.&lt;/li&gt;
&lt;li&gt;Inside this bounding box it calculates the base location of the desired number of clusters.&lt;/li&gt;
&lt;li&gt;It runs through the collection again and adds each overlay to the nearest base location.&lt;/li&gt;
&lt;li&gt;Each base location is moved to the average location of the associated overlays.&lt;/li&gt;
&lt;li&gt;It runs through each updated base location and places a marker at that location&lt;/li&gt;
&lt;li&gt;Each marker gets the contained overlays associated as an attached property.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The OverlayManager doesn't treat cluster markers as regular markers, but keeps them separated. When they are clicked the OverlayManager reads the ContainedOverlays attached property and displays the associated markers. If you are using some other way to store the markers (ex a WCF call) then you need to handle either the ClusterOpening or ClusterOpened event of the OverlayManager.&lt;/p&gt;
&lt;p&gt;You can define the clustering directly in XAML directly in XAML like so:&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;UserControl x:Class="MapMap.MainPage"
			 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
			 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
			 xmlns:map="clr-namespace:Microsoft.VirtualEarth.MapControl;assembly=Microsoft.VirtualEarth.MapControl"
			 xmlns:ve="clr-namespace:Reimers.Silverlight.VirtualEarth;assembly=Reimers.Silverlight"&amp;gt;
	&amp;lt;Grid HorizontalAlignment="Stretch"
		  VerticalAlignment="Stretch"&amp;gt;
		&amp;lt;map:Map x:Name="map"&amp;gt;
			&amp;lt;ve:OverlayManager.Manager&amp;gt;
				&amp;lt;ve:OverlayManager&amp;gt;
					&amp;lt;ve:OverlayManager.Clustering&amp;gt;
						&amp;lt;ve:BoundsClustering DesiredClusterCount="9" /&amp;gt;
					&amp;lt;/ve:OverlayManager.Clustering&amp;gt;
				&amp;lt;/ve:OverlayManager&amp;gt;
			&amp;lt;/ve:OverlayManager.Manager&amp;gt;
		&amp;lt;/map:Map&amp;gt;
	&amp;lt;/Grid&amp;gt;
&amp;lt;/UserControl&amp;gt;
&lt;/pre&gt;
&lt;p&gt;One thing to note, clustering is not performed automatically. You must call the ClusterOverlays method on the OverlayManager. This is done to give you the flexibilty to define when to activate the clustering.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 19:05:28 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/clustering-overlays-in-silverlight</guid></item><item><title>Google Maps for Silverlight</title><link>http://www.reimers.dk:80/tutorials/google-maps-for-silverlight</link><description>&lt;p&gt;The title is not exactly correct if you had expected the cool DeepZoom maps with Google's imagery. Now you know :-)&lt;/p&gt;
&lt;p&gt;What I am talking is a Silverlight control to display map images from &lt;a href="http://code.google.com/apis/maps/documentation/staticmaps/" style="color: #000000;"&gt;Google's Static Map API&lt;/a&gt;. This means that you can display map imagery in your Silverlight application, and because it's Silverlight, you can use it in your list boxes or whereever you want.&lt;/p&gt;
&lt;p&gt;The StaticMap control supports all the features of the Static Map API v2, which means you can display overlays and many different image types. You can define all the properties directly in XAML or you can bind them to other values in your application.&lt;/p&gt;
&lt;p&gt;So if you don't need all the flash of DeepZoom maps, but need to display some geographic data, then this is what you are looking for.&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;UserControl x:Class="TestApp.MainPage"
			 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
			 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
			 xmlns:map="clr-namespace:Reimers.Silverlight.GoogleMap;assembly=Reimers.Silverlight"
			 xmlns:ve="clr-namespace:Microsoft.VirtualEarth.MapControl;assembly=Microsoft.VirtualEarth.MapControl"&amp;gt;
	&amp;lt;map:StaticMap Coordinates="51.477,0"
				   Width="400"
				   Height="400"
				   Zoom="10"
				   GoogleKey="Your Google Key"
				   MapType="Satellite"&amp;gt;
		&amp;lt;map:StaticMap.Overlays&amp;gt;
			&amp;lt;map:StaticMarker MarkerColor="Yellow"
							  MarkerSize="Mid"
							  Point="51.477,0" /&amp;gt;
			&amp;lt;map:StaticMarker MarkerColor="Brown"
							  MarkerSize="Mid"
							  Point="51.577,0.1" /&amp;gt;
			&amp;lt;map:StaticPolyline LineColor="Green"
								Width="5"&amp;gt;
				&amp;lt;map:StaticPolyline.Points&amp;gt;
					&amp;lt;ve:Location Latitude="51.477"
								 Longitude="0" /&amp;gt;
					&amp;lt;ve:Location Latitude="51.577"
								 Longitude="0.1" /&amp;gt;
				&amp;lt;/map:StaticPolyline.Points&amp;gt;
			&amp;lt;/map:StaticPolyline&amp;gt;
		&amp;lt;/map:StaticMap.Overlays&amp;gt;
	&amp;lt;/map:StaticMap&amp;gt;
&amp;lt;/UserControl&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Currently it is available in the SVN trunk, but it will be included in the next release of the Reimers.Silverlight assembly.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 19:04:21 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/google-maps-for-silverlight</guid></item><item><title>Using the OverlayManager</title><link>http://www.reimers.dk:80/tutorials/using-the-overlaymanager</link><description>&lt;p&gt;The OverlayManager (Reimers.Silverlight.Bing.OverlayManager) is intended to facilitate displaying overlays on the Bing Maps Silverlight control. The map control is very good for displaying map imagery, but in my opinion it gives you too much flexibility when it comes to displaying overlays. Let's face it, there's so much you can do in the Silverlight world, that it's easy to get overwhelmed. The OverlayManager is intended to help you perform common tasks when it comes to displaying overlays on a map.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;Setting up the OverlayManager&lt;/p&gt;
&lt;p&gt;So what can you do with it? Well, in short, you can display overlays on your map in an easy straightforward way. The first step is to attached it to your map. The OverlayManager class defines an attached property called ManagerProperty. This means you can connect the OverlayManager with the map directly in XAML, like so:&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;ve:Map x:Name="map"
		ScaleVisibility="Collapsed"
		NavigationVisibility="Collapsed"
		LogoVisibility="Collapsed"
		MouseWheel="map_MouseWheel"&amp;gt;
	&amp;lt;reimers:OverlayManager.Manager&amp;gt;
		&amp;lt;reimers:OverlayManager&amp;gt;&amp;lt;/reimers:OverlayManager&amp;gt;
	&amp;lt;/reimers:OverlayManager.Manager&amp;gt;
&amp;lt;/ve:Map&amp;gt;
&lt;/pre&gt;
&lt;p&gt;You can of course also set it in code. In this case you assign the map object to the RelatedMap property. (I know, this is not good naming convention, but if you look at it, then it seems counter-intuitive to define a property in XAML called RelatedMap, when you are in fact creating an OverlayManager, and likewise it is not easy to understand that in code you are assiging the map object to the Manager property. So I went with the difference). Defining it in code is like setting any other property:&lt;/p&gt;
&lt;p&gt;C#&lt;/p&gt;
&lt;pre class="brush: csharp;"&gt;OverlayManager manager = new OverlayManager();
manager.RelatedMap = map;
&lt;/pre&gt;
&lt;p style="font-weight: bold;"&gt;Adding Overlays&lt;/p&gt;
&lt;p&gt;When the map and OverlayManager have been connected it will make some alterations to the map in order to improve overlay display and you are ready to start adding overlays, that inherit from FrameworkElement. Since the OverlayManager class inherits from a generic collection, you can add overlays to it directly in XAML, like so:&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;reimers:OverlayManager.Manager&amp;gt;
	&amp;lt;reimers:OverlayManager&amp;gt;
		&amp;lt;Image Source=""&amp;gt;
			&amp;lt;ve:MapLayer.MapPosition&amp;gt;
				&amp;lt;ve:Location Latitude="51.477"
							 Longitude="0.0" /&amp;gt;
			&amp;lt;/ve:MapLayer.MapPosition&amp;gt;
		&amp;lt;/Image&amp;gt;
		&amp;lt;ve:MapPolyline Stroke="Blue"
						StrokeThickness="5"&amp;gt;
			&amp;lt;ve:MapPolyline.Locations&amp;gt;
				&amp;lt;ve:LocationCollection&amp;gt;
					&amp;lt;ve:Location Latitude="48.85"
								 Longitude="2.4333" /&amp;gt;
					&amp;lt;ve:Location Latitude="51.477"
								 Longitude="0" /&amp;gt;
				&amp;lt;/ve:LocationCollection&amp;gt;
			&amp;lt;/ve:MapPolyline.Locations&amp;gt;
		&amp;lt;/ve:MapPolyline&amp;gt;
	&amp;lt;/reimers:OverlayManager&amp;gt;
&amp;lt;/reimers:OverlayManager.Manager&amp;gt;
&lt;/pre&gt;
&lt;p&gt;One thing to notice here is the way that the image defines its geographic coordinates. Where the MapPolyline has a Locations property that defines the points on the line, the marker doesn't have the same. So it has to use an attached property defined in the MapLayer class (Microsoft.VirtualEarth.MapControl.MapLayer) so you will need to include that namespace in your XAML. The MapLayer also defines other attached properties like PositioningMethod which defines how the marker is positioned in relation to its coordinates.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;Manipulating Overlays&lt;/p&gt;
&lt;p&gt;Now that you've got overlays added to the manager you are ready to use some of the other features of the OverlayManager.&lt;/p&gt;
&lt;p&gt;The manager allows you to manipulate managed overlays. For example you can make overlays draggable by calling the MakeDraggable method, and inversely you can make it 'undraggable' by calling the MakeFixed method.&lt;/p&gt;
&lt;p&gt;If you are working with shapes (polylines and polygons) then you can edit them on the map by calling the EnableEditing. This will put them into an edit mode where you can drag the vertices into new positions. To disable further editing simply call DisableEditing.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;Display Related Information&lt;/p&gt;
&lt;p&gt;One of the frequent uses for markers is to display related information. In traditional map applications this is done by opening a text bubble when a marker is clicked. This is not directly supported in the Silverlight map control, but the OverlayManager defines an attached property called InfoContent. You can attach this to any overlay. If the overlay is clicked and the manager detects an attached info content it will attempt to display it with the marker so you can display related information. This is how it may look in XAML&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;Image Source=""&amp;gt;
	&amp;lt;ve:MapLayer.MapPosition&amp;gt;
		&amp;lt;ve:Location Latitude="51.477"
					 Longitude="0.0" /&amp;gt;
	&amp;lt;/ve:MapLayer.MapPosition&amp;gt;
	&amp;lt;reimers:OverlayManager.InfoContent&amp;gt;
		&amp;lt;Border BorderBrush="Black"
				BorderThickness="2"
				Width="50"
				Height="50"&amp;gt;
			&amp;lt;TextBlock Text="Hello World" /&amp;gt;
		&amp;lt;/Border&amp;gt;
	&amp;lt;/reimers:OverlayManager.InfoContent&amp;gt;
&amp;lt;/Image&amp;gt;
&lt;/pre&gt;
&lt;p&gt;When trying to open the info content the OverlayManager passes the DataContext of the overlay to the info content, so you can use bindings in your template.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;Clustering&lt;/p&gt;
&lt;p&gt;So now you've got through how to add overlays, and how to display related information. But what happens when you've added too many markers? As opposed to AJAX map applications, Silverlight won't care. It doesn't choke when you display hundreds (or even thousands) of overlays. But that doesn't mean it doesn't overload your users' brains. In this case you may want to cluster your overlays together to reduce clutter.&lt;/p&gt;
&lt;p style="font-weight: bold;"&gt;KML Support&lt;/p&gt;
&lt;p&gt;Apart from the above way to add overlays by code or XAML, you can also read a KML file into the manager by calling the ReadKml method, or write it out using the WriteKml method.&lt;/p&gt;
&lt;p&gt;The OverlayManager lets you attach some extra information to facilitate interaction with KML. The KmlOptions is another attached property that can be attached to your overlays. This lets you define some information in a structure that is recognized by KML.&lt;/p&gt;
&lt;p&gt;The KML definition is very lengthy and only a subset is relevant for displaying overlays in Silverlight, so the OverlayManager may not read all your KML as you expect. It is a work in progress, so if you have any KML files that are not being read properly please let me know so I can improve the parser.&lt;/p&gt;
&lt;p&gt;XAML&lt;/p&gt;
&lt;pre class="brush: html;"&gt;&amp;lt;ve:MapPolyline Stroke="Blue"
				StrokeThickness="5"&amp;gt;
	&amp;lt;reimers:OverlayManager.KmlOptions&amp;gt;
		&amp;lt;kml:KmlOptions Name="Line"
						Description="London - Paris" /&amp;gt;
	&amp;lt;/reimers:OverlayManager.KmlOptions&amp;gt;
	&amp;lt;ve:MapPolyline.Locations&amp;gt;
		&amp;lt;ve:LocationCollection&amp;gt;
			&amp;lt;ve:Location Latitude="48.85"
						 Longitude="2.4333" /&amp;gt;
			&amp;lt;ve:Location Latitude="51.477"
						 Longitude="0" /&amp;gt;
		&amp;lt;/ve:LocationCollection&amp;gt;
	&amp;lt;/ve:MapPolyline.Locations&amp;gt;
&amp;lt;/ve:MapPolyline&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Please report any issues you may experience using the OverlayManager so it can be improved for yourself and others.&lt;/p&gt;
&lt;script type="text/javascript"&gt;// &lt;![CDATA[
SyntaxHighlighter.all();
// ]]&gt;&lt;/script&gt;</description><pubDate>Mon, 13 Jun 2011 19:03:09 GMT</pubDate><guid isPermaLink="true">http://www.reimers.dk:80/tutorials/using-the-overlaymanager</guid></item></channel></rss>
