Monday, July 13, 2009

Silverlight 3 beta 1 and Virtual Earth part 2 (The Map)

In my previous post I covered getting GEO spatial data into SQL and creating a service Silverlight can use to get the data in a usable format. In this post we are going to talk about how to create a Silverlight application to overlay geo spatial data on the Virtual Earth map. First thing first. Download the Silverlight Virtual Earth map control. Once you have done that start a new Visual Studio 2008 Silverlight project and add a reference to the Microsoft.VirtualEarth.MapControl and copy the following code into the XAML of your default window or page.
<Grid x:Name="LayoutRoot" Background="White">
    <m:Map Name="MyMap" ZoomLevel="4" Center="39.36830,-95.27340" Grid.Row="1"/>
</Grid>

Make sure you add this namespace as well for the VE add-in

xmlns:m="clr-namespace:Microsoft.VirtualEarth.MapControl;assembly=Microsoft.VirtualEarth.MapControl"

That is all you have to do. If you run your application you should now have a VE map on it. Now lets get to the fun stuff. In your code behind for the page add a using statement to Microsoft.VirtualEarth.MapControl and add a service reference to the web service you created to provide the spatial data.  Here is what my initialization method looks like:

InitializeComponent();
 
SLSpatialTypesService.SpatialTypeServiceClient serviceClient = new GovSage.SLSpatialTypesService.SpatialTypeServiceClient();
serviceClient.GetCongDistsAsync();
serviceClient.GetCongDistsCompleted += new EventHandler<GovSage.SLSpatialTypesService.GetCongDistsCompletedEventArgs>
    (serviceClient_GetCongDistsCompleted);

As you can see all I am doing is instantiating my service and setting up an event callback for when the call completes. The real work happens when this call comes back.

   1: void serviceClient_GetCongDistsCompleted(object sender, GovSage.SLSpatialTypesService.GetCongDistsCompletedEventArgs e)
   2: {
   3:     foreach (KeyValuePair<string, ObservableCollection<string>> locations in e.Result)
   4:     {
   5:         MapPolyline polyline = new MapPolyline();
   6:         polyline.Stroke = new SolidColorBrush(Colors.White);
   7:         polyline.StrokeThickness = 1;
   8:         polyline.Opacity = 0.5;
   9:         polyline.Locations = new LocationCollection();
  10:         polyline.Name = locations.Key;
  11:         
  12:         foreach (string location in locations.Value)
  13:         {
  14:             string[] latlong = location.Split(new char[] {','});
  15:             Location thisLocation = new Location(Double.Parse(latlong[0]), Double.Parse(latlong[1]));
  16:            
  17:             polyline.Locations.Add(thisLocation);
  18:         }
  19:  
  20:         switch (MyMap.Children.Count)
  21:         {
  22:             case 1:
  23:                 polyline.Fill = new SolidColorBrush(Colors.Blue);
  24:                 break;
  25:             case 2:
  26:                 polyline.Fill = new SolidColorBrush(Colors.Green);
  27:                 break;
  28:             case 3:
  29:                 polyline.Fill = new SolidColorBrush(Colors.Purple);
  30:                 break;
  31:             case 4:
  32:                 polyline.Fill = new SolidColorBrush(Colors.Red);
  33:                 break;
  34:             case 5:
  35:                 polyline.Fill = new SolidColorBrush(Colors.Yellow);
  36:                 break;
  37:             case 6:
  38:                 polyline.Fill = new SolidColorBrush(Colors.Brown);
  39:                 break;
  40:             case 7:
  41:                 polyline.Fill = new SolidColorBrush(Colors.LightGray);
  42:                 break;
  43:             default:
  44:                 polyline.Fill = new SolidColorBrush(Colors.Cyan);
  45:                 break;
  46:         }
  47:         polyline.MouseEnter += new MouseEventHandler(polyline_MouseEnter);
  48:         polyline.MouseLeave += new MouseEventHandler(polyline_MouseLeave);
  49:         MyMap.Children.Add(polyline);
  50:     }
  51: }

I get a KeyValuePair back from the web service. To create all my overlays I loop through each key value I get back. My key is my area name and the second value is an ObservableCollection of type string. In the first few lines (5-10) all I am doing is creating a new MapPolyline for each item and setting its properties and instantiating its LocationCollection. Then for each item in my ObservableCollection I loop and create a new location in my polyline. All I have to do is split the string value on the “,” and create a new location based on the latitude and longitude I am return and add it to the location collection. In my case I create 7 different MapPolyline objects each having about a hundred locations attached to them. 

At this point I have created all the objects I need to overlay on my map. Once I leave the inner foreach statement I hit a case statement that simply looks at how many children my map has and sets the polyline fill color for that object to a certain color. This allows each overlay area to have a different color.

Down at line 47 I start the code to add each MapPolyline to my map. Once you have added each as a child you should now be able to load your map and see your overlays (just make sure the latitude and longitude items you added for your locations actually matches the area you are expecting. If not your MapPolylines may get added to a completely different area of the map).

My map now looks like this and as I move in and out my MapPolylines adjust as well.

 

image

If your map scrolling is not smooth you need to do more reducing (reducing was talked about in part 1).

1 comment:

Anonymous said...
This comment has been removed by a blog administrator.