Summary: A little exercise using ESRI Silverlight API just to get started with the framework. Simply using the code samples ESRI provides like Lego building blocks.
Back when I was interviewing to my current position, the interviewer (my current team leader) gave me a station with the interactive Silverlight SDK and asked me to change one of the examples so that when selecting a polygon all the polygons that are smaller in area size from the selected polygon will also be selected. That was my first interaction with Silverlight (with ESRI I have worked before).
In this post I am just going to implement that exercise.
This example uses version 2.1 of the API (the current version). It can be downloaded from here (you will have to register to a ESRI Global Account but it is free).
First lets compile the solution and choose the base for the application, I have chosen Query->Spatial Query (which implements selection from the map):
Now the code behind and the xaml is a mess (because of all the extra functionality) so I will just remove some things (just keep the point selection):
The symbol for the results:
- <Grid.Resources>
- <esri:FillSymbol x:Key="ResultsFillSymbol" BorderBrush="Blue" BorderThickness="5"/>
- </Grid.Resources>
The map with one layer for the background and an event for the mouse click:
- <esri:Map x:Name="MapControl" Extent="-15000000,2000000,-7000000,8000000" MouseClick="MapControl_MouseClick">
- <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"/>
- </esri:Map>
And last a canvas for the buttons of Point selection and Clear (that you can see here).
The code behind (in the next post I will do this with the MVVM pattern) contains the handlers for the two buttons (simply turning a flag on or off):
- private void PointButton_Click(object sender, RoutedEventArgs e)
- {
- _selectionMode = true;
- StatusTextBlock.Text = "Select by clicking at point location";
- }
(the clear looks the same)
The map click event only works when the selection mode is on:
- private void MapControl_MouseClick(object sender, Map.MouseEventArgs mouseEventArgs)
- {
- if (_selectionMode)
- QueryContainingGeometry(mouseEventArgs.MapPoint);
- }
- private void QueryContainingGeometry(Geometry geometry)
- {
- _selectionGraphicsLayer.ClearGraphics();
- var queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5");
- queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted;
- queryTask.Failed += (sender, args) => MessageBox.Show("Query failed: " + args.Error);
- var query =
- new Query
- {
- Geometry = geometry,
- ReturnGeometry = true,
- OutSpatialReference = MapControl.SpatialReference
- };
- queryTask.ExecuteAsync(query);
- }
QueryContainingGeometry method does a query against the States layer in ArcGis Server and returns the result to:
- private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args)
- {
- var featureSet = args.FeatureSet;
- if (featureSet == null || featureSet.Features.Count < 1)
- {
- MessageBox.Show("No features returned from query");
- return;
- }
- foreach (var feature in featureSet.Features)
- {
- feature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as FillSymbol;
- _selectionGraphicsLayer.Graphics.Add(feature);
- }
- }
Here we go over the results and add them to a graphics layer (we created it in the constructor) using the symbol from the xaml.
Until now the code was mostly ESRI’s example (as I said I removed some of it and refactored a bit more): the full xaml can be found here, and the code behind here.
But now we start with the actual exercise. We are going to use the field SQMI which is the square miles of the state.
The first thing we do is change QueryTask_ExecuteCompleted so that it executes a query:
- var minimumSquareMiles = int.MaxValue;
- foreach (var feature in featureSet.Features)
- {
- feature.Symbol = LayoutRoot.Resources["FirstStateSymbol"] as FillSymbol;
- _selectionGraphicsLayer.Graphics.Add(feature);
- minimumSquareMiles = Math.Min(minimumSquareMiles, (int) feature.Attributes["SQMI"]);
- }
- QueryByArea(minimumSquareMiles);
In line 4 I changed the symbol being used just so we could see the first state as opposed to the ending states.
QueryByArea looks like:
- private void QueryByArea(int minimumSquareMiles)
- {
- var queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Census_USA/MapServer/5");
- queryTask.ExecuteCompleted += QueryAreaTask_ExecuteCompleted;
- queryTask.Failed += (sender, args) => MessageBox.Show("Query failed: " + args.Error);
- var query =
- new Query
- {
- Where = "SQMI > " + minimumSquareMiles,
- ReturnGeometry = true,
- OutFields = new OutFields { "*" },
- OutSpatialReference = MapControl.SpatialReference
- };
- queryTask.ExecuteAsync(query);
- }
This time instead of querying by a geometry, we query by a where clause.
QueryAreaTask_ExecuteCompleted just adds the results to graphics feature layer:
- private void QueryAreaTask_ExecuteCompleted(object sender, QueryEventArgs args)
- {
- var featureSet = args.FeatureSet;
- if (featureSet == null || featureSet.Features.Count == 0)
- return;
- foreach (var feature in featureSet.Features)
- {
- feature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as FillSymbol;
- _selectionGraphicsLayer.Graphics.Add(feature);
- }
- }
And that’s it. The result looks like this:
The source code can be found here.
On the next post I will walk you through on how to turn this application from a code behind application to a MVVM patterned application.
Keywords: Silverlight, ESRI