In my previous post I described how to create a simple Silver Light Application to show the Bing Map and add one location on the map.In this article I will step through the process to add multiple locations on the Bing Map by fetching the data from a XML file
Recently I came across a requirement to show multiple locations on the map. First thing came into my mind is Google Map – the well known. Google Map is adding locations on the map by using Java script. I successfully implemented that.
But I noticed that when there are more than 1000 locations to show on the map, the web page hangs up and gives error that “A script on this page is causing Internet Explorer to run slowly. If it continues to run, your computer may become unresponsive. Do you want to abort the script?”
After searching a bit I got solution to use Bing Map with Silverlight. With Bing Map & Silverlight, it's become quite easy to develop a mapping web application with visually enhanced graphics and smooth transition effects.
To start Create a Silverlight project which shows the Bing Map centered to New York. See my article ”Getting Started with Bingmap in Silverlight” for more information.
I assume that we have a XML file called CustomerData.xml with information of Longitude and Latitude of the all the customers which we need to show up on the map. See of sample the XML File here
<?xml version="1.0" encoding="utf-8"?>
<Aide>
<Cust CustID="10001" CustomerName="Aaron" Latitude="43.778926" Longitude="-73.958068" />
<Cust CustID="10002" CustomerName="Gabriel" Latitude="41.003764" Longitude="-75.494192" />
<Cust CustID="10003" CustomerName="Jack" Latitude="40.941352" Longitude="-73.871310" />
<Cust CustID="10004" CustomerName="Dale" Latitude="40.930429" Longitude="-73.900575" />
<Cust CustID="10005" CustomerName="Maddox" Latitude="40.923250" Longitude="-73.794536" />
<Cust CustID="10006" CustomerName="Paul" Latitude="40.886874" Longitude="-73.857243" />
<Cust CustID="10008" CustomerName="Samson" Latitude="40.885397" Longitude="-73.849536" />
<Cust CustID="10009" CustomerName="Vance" Latitude="40.883922" Longitude="-73.863246" />
<Cust CustID="10010" CustomerName="Abbott" Latitude="40.882452" Longitude="-73.896702" />
<Cust CustID="10011" CustomerName="Dalton" Latitude="40.876592" Longitude="-73.879747" />
<Cust CustID="10012" CustomerName="Gale" Latitude="40.876429" Longitude="-73.911809" />
<Cust CustID="10013" CustomerName="Jacob" Latitude="40.874241" Longitude="-73.887638" />
<Cust CustID="10014" CustomerName="Magnus" Latitude="40.873976" Longitude="-73.866702" />
<Cust CustID="10090" CustomerName="Jeremy" Latitude="40.653881" Longitude="-73.852000" />
</Aide>
I will describe the process of getting the Longitude and Latitude of an address in my subsequent post.
Location Class
Namespace Microsoft.Maps.MapControl have a class Location. This class have two properties Longitude and Latitude. Let’s create a class for to store Customer’s Location data in the XML file.
public class LocationData
{
public Location Location
{
get;
set;
}
public String CustomerName
{ get; set; }
public Int32 CustomerId
{ get; set; }
public LocationData()
{
this.Location = new Location();
}
}
This class contains an embedded Location object. It acts as DataContext for the individual items within MapItemsControl. Thus {Binding Location} translates to LocationData.Location
Location Data Collection
Now let’s create a collection of LocationData class to fetch the data from XML File. This class exposes IEnumerable, and acts as ItemsSource for MapItemsControl
public class LocationDataCollection : ObservableCollection
{
public bool IsDataSource
{
get
{
return true;
}
set
{
this.Load();
}
}
public LocationDataCollection()
{
}
}
Reading XML File
Put the CustomerData.xml file in ClientBin Folder of web project.
Add reference of System.Xml.Serialization Namespace.
Now create a Load Function in LocationDataCollection Class to read the xml file and pouplate the LocationDataCollection
public void Load()
{
Uri url = new Uri("CustomerData.xml", UriKind.Relative);
WebClient client = new WebClient();
client.DownloadStringCompleted += new
DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(url);
}
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
StringReader stream = new StringReader(e.Result);
XmlReader reader = XmlReader.Create(stream);
Double Lat = 0.00;
Double Lng = 0.00;
String CustomerName = "";
Int32 CustomerId = 0;
LocationDataCollection locationList = new LocationDataCollection();
while (reader.Read())
{
reader.MoveToContent();
if (reader.NodeType == XmlNodeType.Element)
{
reader.MoveToFirstAttribute();
}
if (reader.NodeType == XmlNodeType.Attribute)
{
if (true == reader.MoveToAttribute("Latitude"))
{
Lat = reader.HasValue ? Convert.ToDouble(reader.Value) : 0.00;
}
if (true == reader.MoveToAttribute("Longitude"))
{
Lng = reader.HasValue ? Convert.ToDouble(reader.Value) : 0.00;
}
if (true == reader.MoveToAttribute("CustomerName"))
{
CustomerName = reader.Value.ToString();
}
if (true == reader.MoveToAttribute("CustID"))
{
CustomerId = Convert.ToInt32(reader.Value);
}
LocationData T = new LocationData();
T.Location.Latitude = Lat;
T.Location.Longitude = Lng;
T.CustomerName = CustomerName;
locationList.Add(T);
}
}
IEnumerator ppEnum = locationList.GetEnumerator();
while (ppEnum.MoveNext())
{
this.Add((LocationData)ppEnum.Current);
}
reader.Close();
}
}
PushPin
In Bing Map’s terminology Icon show on the Map is called PushPin.
Now modify the xaml for the MainPage.xaml user control by adding an xml namespace declaration of current Project
xmlns:t="clr-namespace:Demo1"
Here Demo1 is the name of the project. We need to add tag above so that the class LocationDataCollection is available in MainPage.xaml.
So the complete UserControl tag will appear as:
<UserControl x:Class="Demo1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
xmlns:t="clr-namespace:Demo1"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
To add multiple pushpins on the map, let’s create a DataTemplete. Add following inside the UserControl above the Grid Tag:
<UserControl.Resources>
<DataTemplate x:Key="LogoTemplate">
<m:Pushpin m:MapLayer.Position="{Binding Location}" >
<ToolTipService.ToolTip >
<TextBlock Text="{Binding CustomerName}"></TextBlock>
</ToolTipService.ToolTip>
</m:Pushpin>
</DataTemplate>
<t:LocationDataCollection x:Key="LocationList" IsDataSource="True"/>
</UserControl.Resources>
A couple of things to understand here:
- UserControl.Resources – is used to define the style for controls in Silverlight
- LogoTemplate is a new DataTemplate.
- Following is creating a object of LocationDataCollection class called LocationList
<t:LocationDataCollection x:Key="LocationList" IsDataSource="True"/>
- Following will add a Pushpin on the map. Location of the pushpin is coming in Location property of item source
<m:Pushpin m:MapLayer.Position="{Binding Location}" ></m:Pushpin>
- Following will show the name of the customer as tooltip when mouse moved to a pushpin on the map.
<ToolTipService.ToolTip >
<TextBlock Text="{Binding CustomerName}"></TextBlock>
</ToolTipService.ToolTip>
Let’s now add the MapItemControl in the map. MapItemControl class represents a class that uses a MapLayer as an ItemsPanel. This enables data binding using an ItemsSource and an ItemTemplate. This class inherits from the ItemsControl class.
<m:Map x:Name="MyMap" CredentialsProvider="Your Key"
Mode="Road" RenderTransformOrigin="0.42,0.557" Margin="0,0,0,0"
LogoVisibility="Collapsed" >
<m:MapItemsControl x:Name="ListOfItems"
ItemTemplate="{StaticResource LogoTemplate}"
ItemsSource="{StaticResource LocationList}">
</m:MapItemsControl>
</m:Map>
Press F5 and see what you have the map. The Map shows multiple pushpins on the map!!! Also if you move the mouse over the pushpin it will show you the name of the customer.
I guess it looks great!!! You can download the source from here.
But still my boss doesn’t like that much. He had a few problems
- Icons on the map is too big.
- More information to show on tool tip.
- Make the tool tip attractive.
He asked me to look at following URL.
http://projects.nytimes.com/crime/homicides/map
Although it is in Flash, he wanted to build similar in Silverlight. That seems a BIG Challenge.
In the next article I will show how to build similar….