Monthly Archives: June 2012

Generic Bing maps pushpin clustering component for Windows Phone 7

A couple of weeks ago I wrote my own Windows Phone app Lovely Neighbourhood which is showing pushpins on the Bing maps control for Windows Phone 7. Because there where quit some pushpins close to each other I decided to use pushpin clustering (sometimes called marker clustering) to make map in the app look less chaotic than with all the pushpins on the map. (There where a few regions where you couldn’t even see the map anymore.)

After a little search I found a blog post by Colin Eberhardt who has a guide to pushpin clustering in WP7. I started implementing and after a few changes it works fine in my app. But than I saw an app from my colleague which was not using pushpin clustering and also on his map view it was pretty hard to see the map. At that moment I started thinking about rewriting the pushpin clustering code in a generic way, so it would be easy to implement in any app.

In this article I want to show you how to use my pushpin clustering component in your app.

The first step that you need to do is add a reference to the PushPinClusterer.dllin your project.

The next step will be to add the IClusteredGeoObject interface to your entity which has the GeoCoordinate property.

1 public class MyGeoObject : IClusteredGeoObject 2 { 3 public string Name { get; set; } 4 public string Country { get; set; } 5 6 public GeoCoordinate Coordinate { get; set; } 7 8 }

When you implement the interface, you have to implement the Coordinate property which is of type GeoCoordinate. You can just use this property as your location property, or in the getter/setter return/set your own GeoCoordinate property. After implementing the IClusteredGeoObject your entity is ready to be clustered.

The next step will be to setup your xaml so you have a layer where you can add the pushpins and a DataTemplate so you can make a difference between the objects you want to show on the map in case of a clustered pushpin or a normal pushpin.

Below you find the XAML for my Bing maps control with the MapItemsControl where I bind the ObservableCollection<T> from my pushpin clusterer and we reference the “pushpinSelector” datatemplate.

1 <my:Map Height="601" Name="map1" Width="456"> 2 <my:MapItemsControl Name="pushPinModelsLayer" 3 ItemsSource="{Binding PushpinModels}" 4 ItemTemplate="{StaticResource pushpinSelector}" /> 5 </my:Map>

The next step is adding the datatemplate to our resources section like below:

1 <DataTemplate x:Key="pushpinSelector"> 2 <my:Pushpin Location="{Binding Location}" CacheMode="BitmapCache"> 3 <my:Pushpin.Template> 4 <ControlTemplate> 5 <clusterer:PushpinTemplateSelector Content="{Binding}"> 6 <clusterer:PushpinTemplateSelector.ClusterTemplate> 7 <DataTemplate> 8 <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> 9 <Ellipse Fill="Red" Width="40" Height="40" /> 10 <TextBlock Foreground="White" Text="{Binding ClusterCount}" 11 HorizontalAlignment="Center" VerticalAlignment="Center" /> 12 </Grid> 13 </DataTemplate> 14 </clusterer:PushpinTemplateSelector.ClusterTemplate> 15 <clusterer:PushpinTemplateSelector.PushpinTemplate> 16 <DataTemplate> 17 <StackPanel Background="Black"> 18 <TextBlock Text="{Binding CurrentObject.Name}" Foreground="White" /> 19 </StackPanel> 20 </DataTemplate> 21 </clusterer:PushpinTemplateSelector.PushpinTemplate> 22 </clusterer:PushpinTemplateSelector> 23 </ControlTemplate> 24 </my:Pushpin.Template> 25 </my:Pushpin> 26 </DataTemplate>

As you can see in the above xaml markup we have two pushpin templates, one for the clustered pushpins and one for the normal pushpins. The pushpin clusterer is telling you how many pushpins there are clustered by binding the Count property. In the “normal” pushpin you will get your object back from the binding by calling the CurrentObject property. So if you have a property Name on your entity you can bind it here by calling CurrentObject.Name.

The only thing we now have to do is load our data, for example in the OnNavigatedTo event where you can load the list of entities which have IClusteredGeoObject implemented. The following code can be used to start clustering your pushpins.

1 var clusterer = new PushpinClusterer<MyGeoObject>(map1, pins, 50); 2 pushPinModelsLayer.DataContext = clusterer;

When instantiating the PushPinClusterer you give the Type of your entity to the clusterer and as parameters the map you have defined in your xaml, the list of entities and an integer with the distance in pixels in which pushpins have to be clustered.

If you need to know when the clustering is complete you can subscribe to the ClusteringCompleted event, which will fire when it is finished clustering the pushpins.

That’s it, if you start your app now it will start clustering your pushpins.

I have created an example solution with the steps as described above, which you can download from my blog.

Hope this will help you adding pushpin clustering to your app, and I love to hear it from you if used it and in which app. If you have any questions, suggestions or anything else you can contact me on twitter by using @bloodyairtimer or leave a comment on this post.

Happy coding!