In the last post we introduced the helpers that are available in the Phone toolkit for the Map control in Windows Phone 8: the map control is much more powerful than the one that is available in Windows Phone 7, but it lacks some controls that were widely used, like pushpins. In the previous post we’ve seen how to add a pushpin and place it in a specific position: it was an interesting experiment, but not really useful, because most of the times we need to place many pushpins on the same layer.

Let’s see how to do it using some features that every Windows Phone developer should know: template and binding.

Back to work

Let’s imagine that we’re going to display some restaurants that are near the user’s location. For this reason, the first thing we need is a class to map this information:

public class Restaurant
{
    public GeoCoordinate Coordinate { get; set; }
    public string Address { get; set; }
    public string Name { get; set; }
}

After that, we need a way to define a template to display a collection of Restaurant’s object over the map: we’re going to use one of the helpers available in the toolkit.

<maps:Map x:Name="myMap">
    <toolkit:MapExtensions.Children>
        <toolkit:MapItemsControl Name="RestaurantItems">
            <toolkit:MapItemsControl.ItemTemplate>
                <DataTemplate>
                    <toolkit:Pushpin GeoCoordinate="{Binding Coordinate}" Content="{Binding Name}" />
                </DataTemplate>
            </toolkit:MapItemsControl.ItemTemplate>
        </toolkit:MapItemsControl>
    </toolkit:MapExtensions.Children>
</maps:Map>

We use again the MapExtensions.Children that we’ve learned to use in the previous post. Then we introduce the MapItemsControl, which is a control that is able to display a collection of objects over the map. Think of it like a ListBox control, but in this case the elements that are part of the collection are displayed over the map, as a new layer. The most interesting feature of this control is that, like other controls that are used to display collections, it supports templating: we can define the template (the ItemTemplate property) of a single object, that will be used to render every object that is part of the collection. In this sample, we define as a template a Pushpin object, which Content and GeoCoordinate properties are in binding with the properties of the Restaurant class. This means that, in the code, we’re going to assign to the ItemSource property of the MapItemsControl a collection of restaurants: the control is going to render a Pushpin for every restaurant in the collection and will place it on the map, in the position defined by the GeoCoordinate property.

Here is how we do it:

public MainPage()
{
    InitializeComponent();
    Loaded+=MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    ObservableCollection<Restaurant> restaurants = new ObservableCollection<Restaurant>() 
    {
        new Restaurant { Coordinate = new GeoCoordinate(47.6050338745117, -122.334243774414), Address = "Ristorante 1" },
        new Restaurant() { Coordinate = new GeoCoordinate(47.6045697927475, -122.329885661602), Address = "Ristorante 2" },
        new Restaurant() { Coordinate = new GeoCoordinate(47.605712890625, -122.330268859863), Address = "Ristorante 3" },
        new Restaurant() { Coordinate = new GeoCoordinate(47.6015319824219, -122.335113525391), Address = "Ristorante 4" },
        new Restaurant() { Coordinate = new GeoCoordinate(47.6056594848633, -122.334243774414), Address = "Ristorante 5" }
    };

    ObservableCollection<DependencyObject> children = MapExtensions.GetChildren(myMap);
    var obj =
        children.FirstOrDefault(x => x.GetType() == typeof(MapItemsControl)) as MapItemsControl;

    obj.ItemsSource = restaurants;
    myMap.SetView(new GeoCoordinate(47.6050338745117, -122.334243774414), 16);
}

The first thing to highlight is that we’re going to use this code in the Loaded event of the page. This is required because, if we do it in the MainPage constructor, we risk that the code is executed before that every control in the page is rendered, so we may not have access yet to the MapItemsControl object.

First we create some fake restaurants to use for our test and we add it to a collection, which type is ObservableCollection<Restaurant>. Then we need to get a reference to the MapItemsControl object we’ve declared in the XAML, the one called RestaurantItems. Unlucky, due to the particular architecture of the MapExtensions helper provided with the toolkit, we can’t access to the control directly using the Name property, but we need to look for it in the collection of controls inside the Children property of the MapExtensions controls.

To do this, we use the MapExtensions.GetChildren method of the toolkit, passing as parameter our map control. This method returns an ObservableCollection<DependencyObject>, which is a collection of all the controls that have been added. In this case, by using a LINQ query and the GetType() method, we get a reference to the MapItemsControl object. We can use the FirstOrDefault statement because we’ve added just one MapItemsControl inside the MapExtensions.Children collection: once we have a reference, we cast it to the MapItemsControl (otherwise it would be a generic object, so we wouldn’t have access to the specific properties of the MapItemsControl class). Finally, we are able to access to the ItemsSource property, which holds the collection that is going to be displayed over the map using the ItemTemplate we’ve defined in the XAML: we simply assign to this property the fake ObservableCollection<Restaurant> we’ve created before.

For sake of simplicity, we also set the center of the map to the coordinates of the first restaurant: this way will be easier for us to test the code and see if every pushpin is displayed correctly.

And here is the final result:

map

In the end

As you can see, the mechanism is very simple: it’s the usual one that we already use every time we have a collection that we wants to display. We define a collection of objects (usually a ObservableCollection<T>, to have INotifyPropertyChanged support out of the box), we define an ItemTemplate in the XAML and we assign the collection to the ItemsSource property of the control. The only trivial thing, in this case, is to get a reference to the MapItemsControl object, since it can’t be referenced just by using the name as for every other control.

Here is the link to download a sample that recap most of the things we’ve seen in the latest two posts: