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
To do this, we use the MapExtensions.GetChildren method of the toolkit, passing as parameter our map control. This method returns an **ObservableCollection
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:
###
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
Here is the link to download a sample that recap most of the things we’ve seen in the latest two posts: