I don’t generally find the fall or winter an appropriate time to track weather conditions, but this is an exception. Microsoft recently released the Bing Maps Silverlight Control SDK, which ties Silverlight and Bing Maps closely together, allowing developers to create some very powerful mapping applications. In this article, I’ll walk the reader through the process of creating an Europe weather map application in Silverlight by using the Bing Maps Silverlight Control.
Getting started
To use the control in Silverlight projects, you have to download the Bing Maps Silverlight Control SDK and install it. If not already done so, you’ll have to create a Bing Maps Developer Account at https://www.bingmapsportal.com (you’ll need a Windows Live ID). After your account has been created, you’ll have to create at least one Bing Maps key for accessing the Bing Maps services (max 5 keys are allowed). With the key created, you’re ready to create your first Bing Maps Application. One last thing. After creating a Silverlight project in Visual Studio or Blend, make sure you include (Add Reference…) the following libraries in the project: Microsoft.Maps.MapControl.dll and Microsoft.Maps.MapControl.Common.dll.
Getting the data
In order to create a weather map, we need information about the current weather condition. I used XML feeds that our National Environmental Agency provides as a service. There are currently four feeds to choose from – I used the feeds for Europe’s capital and other larger cities.
Each feed provides a bunch of metadata about the feed itself (such as credits, suggested pickup time and period, etc.), as well as a collection of items, describing the weather conditions for included locations. This is an example of an item definition in one of the feeds (short excerpt):
<nn_icon>modCloudy</nn_icon>
<nn_shortText>moderately cloudy</nn_shortText>
<nn_decodeText>5/8 .. 6/8</nn_decodeText>
<wwsyn_icon />
<wwsyn_shortText>Rain</wwsyn_shortText>
<wwsyn_longText>Rain (not freezing)</wwsyn_longText>
<nn_icon-wwsyn_icon>modCloudy</nn_icon-wwsyn_icon>
<t_var_desc>Temperature</t_var_desc>
<t_var_unit>°C</t_var_unit>
<t>8</t>
<t_degreesC>8</t_degreesC>
<windchill />
<vis_value>45</vis_value>
<vis_unit>km</vis_unit>
This XML elements have to be parsed into a valid structure and stored in the database. LINQ2XML query will be used to parse the XML…
var data =
from item in document.Root.Elements("metData")
select new WeatherCondition
{
MeteoId = item.Element("domain_meteosiId").Value,
UpdatedTime = item.Element("tsUpdated_UTC").Value,
City = item.Element("domain_longTitle").Value,
CountryCode = item.Element("domain_countryIsoCode2").Value,
Latitude = decimal.Parse(item.Element("domain_lat").Value,
System.Globalization.CultureInfo.GetCultureInfo("en-us")),
Longitude = decimal.Parse(item.Element("domain_lon").Value,
System.Globalization.CultureInfo.GetCultureInfo("en-us")),
Condition = item.Element("nn_shortText").Value,
ConditionIcon = item.Element("nn_icon").Value,
Weather = item.Element("wwsyn_shortText").Value,
Temperature = int.Parse(item.Element("t").Value),
TemperatureUnit = item.Element("t_var_unit").Value,
Humidity = item.Element("rh").Value.Length == 0 ?
default(int?) : int.Parse(item.Element("rh").Value),
HumidityUnit = item.Element("rh_var_unit").Value,
...
};
… and LINQ2SQL will help us store it into the database…
List<WeatherCondition> items = Collect();
WeatherDataContext context = new WeatherDataContext();
context.ExecuteCommand("delete dbo.WeatherCondition");
context.WeatherConditions.InsertAllOnSubmit(items);
context.SubmitChanges();
Of course, this part was done on the server side. We need to expose this data as a service:
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class WeatherService
{
[OperationContract]
public IEnumerable<WeatherCondition> GetWeatherConditions()
{
return from wc in new WeatherDataContext().WeatherConditions select wc;
}
}
With weather data captured and exposed as a WeatherService, we’re ready to move on to the client part .
Setting up the Map control
The first thing to do after putting a Bing Maps control on a Silverlight page is setting the Bing Maps key you created previously. All the control’s properties can be found under the Miscellaneous section. You set the key by pasting it into the CredentialsProvider field. Don’t worry if the text changes to something else when focusing out of the field; it’s just the name of the ApplicationIdCredentialsProvider object, holding a reference to your key.
<map:Map.CredentialsProvider>
<map:ApplicationIdCredentialsProvider ApplicationId="Your-Key"/>
</map:Map.CredentialsProvider>
There are additional options for controlling what is displayed on the map and how: you can set the
Mode property to either
Road or
Aerial, hide logo, copyright, navigation and scale overlays, set zoom level and initial center point, etc.
Putting data into the context
The map control gets the weather data from the ViewModel, which is responsible for calling the WeatherService to collect the data, whenever required. The MainPageViewModel exposes weather conditions as a collection property to be easily consumed by the control (a common MVVM pattern scenario). The MapItemsControl object adds ItemsControl-like features to the map control, making it bindable to a collection of items, while enabling visual appearance changes to either control itself, and/or bound items.
Each weather condition should be represented by its own icon. There’s another class in the SDK called Pushpin – this one is used to put custom objects on the map. Using it in the MapItemsControl’s ItemTemplate will get all the bound items pinned to the bound location.
Pushpin’s location property can be bound to the underlying object’s location of type Location. Because the Location type is proprietary to the Map control it’s not very likely to be defined and exposed on the server side object. We can, however, extend the client proxy item class to expose the Location property:
namespace WeatherMap.WeatherServiceProxy
{
public partial class WeatherCondition
{
public Location Location
{
get { return new Location((double)Latitude, (double)Longitude) ;}
}
}
}
Displaying weather icons
Each Pushpin should have a look that would correspond to the current weather condition for that place. This could easily be achieved by putting an Image control into the Pushpin template and setting its source to point to an appropriate icon file, possibly through a kind of value converter. Finding this approach being somehow limiting, I went with a bit more flexible way – using a custom template selector, I was able to define how weather would be represented for each condition. The template selector is bound to the CurrentCondtion property, which is a derivate of two parts: the sky cloud coverage (cloudiness) and precipitation (rain, snow, fog, …). Because a lot of different combinations are possible, I simplified the logic by reducing them to the following mapping table:
<local:TemplateSelector x:Name="templateSelector" DataType="{Binding CurrentCondition}">
<local:TemplateSelector.DataTemplates>
<local:TemplateSelectorDataTemplate DataType="clear">
<local:Clear />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="Clear">
<local:Overcast />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="overcast">
<local:Overcast />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="Cloudy">
<local:Cloudy />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="FG">
<local:Fog />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="RA">
<local:Rain />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="SN">
<local:Snow />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate DataType="TH">
<local:Thunder />
</local:TemplateSelectorDataTemplate>
<local:TemplateSelectorDataTemplate>
<TextBlock Text="{Binding CurrentCondition}" />
</local:TemplateSelectorDataTemplate>
</local:TemplateSelector.DataTemplates>
</local:TemplateSelector>
Each template contains a single user control, graphically representing a weather condition. And by graphically, I don’t mean just a static icon (we could have used a simple bitmap icon for that); by using XAML, we can put the icon in motion through various animations.
Lastly, we can create ‘layers’ of presenting different conditions. Using a very simple animation for switching the opacity of two controls, we can transition from an graphics conditions view to the temperature view. The ControlStoryboardAction behavior was used for starting this continuous transition when the page first loaded.
Showing full weather details
Users, wanting to know more information about current conditions, will be able to click on any weather symbol on the map to get the details. A customized ChildWindow control will be used to display the data, and a special ShowWindowAction behavior will be used to show it:
[DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger),
new object[] { "MouseLeftButtonDown" })]
public class ShowChildWindowAction : TriggerAction<FrameworkElement>
{
public string ChildWindowType { get; set; }
protected override void Invoke(object parameter)
{
ChildWindow window = Activator.CreateInstance(
Type.GetType(ChildWindowType, false, true)) as ChildWindow;
if (window == null)
{
return;
}
if (AssociatedObject != null)
{
window.DataContext = AssociatedObject.DataContext;
}
window.Show();
}
}
This behavior simply takes the name of the ChildWindow, and in case of successfully creating a new instance, sets its DataContext to whatever context the associated object had. The ChildWindowType property should be set to a fully qualified object name. This is because Silverlight doesn’t support binding to types.
Summary
Bing Maps Silverlight control is a very powerful, yet simple to use Silverlight control for creating virtually any kind of online location-based visualization application. Its data binding abilities make it “blendable” plus you can use Bing Maps Web Services to (reverse) geocode locations and even calculate a travel route.
This tutorial covered the very basics of creating a Silverlight weather map. Many improvements to the application is in the works, including better graphics (current icons were taken from the Weather Snifferand animated), more accurate information, ability to play back recorded history, etc.
Many additional mapping samples are provided to explore through Bing Maps Silverlight Control Interactive SDK.
Download source code.
Run the Europe weather map application online.