Query task
The Query task allows you to retrieve features from a feature layer in an ArcGIS Server map service or a spatially-enabled table in SQL Server via the MapIt Spatial Data Service. Features can be retrieved using spatial and/or attribute query parameters. Once the features are returned, you can use .NET code to display their geometries and attributes in your ArcGIS API for Windows Phone application. To use a Query task, you will need to include code to define its user interface and specify its execution logic.
Samples of Query tasks are available in the Query section of the Interactive SDK.
Creating a Query task
An example of XAML and .NET code (in this case C#) for a simple Windows Phone application that includes a Query task is shown below. It includes the following steps:
- Creating an input interface for the Query task
- Creating an output interface for the Query task
- Implementing the Query task's execution logic, including:
This application defines a Query task that uses a TextBox control for specifying the query and a button for executing the task. Result features are displayed in a GraphicsLayer.
The following sections assume you have created a Windows Phone application with a map as a base layer as described in Creating a map. The XAML view of your application's ContentGrid in MainPage.xaml should look like the following code:
<Grid x:Name="ContentGrid" Grid.Row="1">
<esri:Map x:Name="MyMap" Extent="-120, 20, -100, 40">
<esri:Map.Layers>
<esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer"
Url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer">
</esri:ArcGISTiledMapServiceLayer>
</esri:Map.Layers>
</esri:Map>
</Grid>

In the example code below, the extent of the Map was changed to "-130, 20, -60, 40" in order to display the full United States.
The code in your code-behind file, MainPage.xaml.cs, should be unchanged from when you created your Windows Phone project in Visual Studio.
Creating an input interface for the Query task
Since tasks do not define user interfaces, you need to implement an interface for the Query task's input to allow your application's users to execute queries. For this, the example simply includes a TextBox for defining the query and a Button to execute the task.
- In the ContentGrid element in the XAML, after the Map element, define a Canvas to hold the task's input interface. Where possible, it is best to use a Canvas as the container element because Silverlight renders these most efficiently.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > </Canvas>
- Specify a Rectangle to use as the background for the input interface. This rectangle will be semi-transparent and have rounded corners.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> </Canvas>
- Add a TextBlock to inform the user how to use the task.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> <TextBlock Text="Type a query and click Execute" Foreground="White" FontSize="22" Margin="10,5,0,0" /> </Canvas>
- Define a TextBox for specifying the query.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> <TextBlock Text="Type a query and click Execute" Foreground="White" FontSize="22" Margin="10,5,0,0" /> <TextBox x:Name="QueryTextBox" Width="300" Margin="8,27,0,0" /> </Canvas>
- Add a default value to the TextBox.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> <TextBlock Text="Type a query and click Execute" Foreground="White" FontSize="22" Margin="10,5,0,0" /> <TextBox x:Name="QueryTextBox" Width="300" Margin="8,27,0,0" Text="POP07_SQMI > 500" /> </Canvas>
- Add a Button to execute the query.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> <TextBlock Text="Type a query and click Execute" Foreground="White" FontSize="22" Margin="10,5,0,0" /> <TextBox x:Name="QueryTextBox" Width="300" Margin="8,27,0,0" Text="POP07_SQMI > 500" /> <Button x:Name="QueryButton" Content="Query" Margin="295,28,0,0" /> </Canvas>
- Specify a handler for the Button's Click event. Later, you will implement this handler so that it executes the query.
<Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="430" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="420" Height="100" /> <TextBlock Text="Type a query and click Execute" Foreground="White" FontSize="22" Margin="10,5,0,0" /> <TextBox x:Name="QueryTextBox" Width="300" Margin="8,27,0,0" Text="POP07_SQMI > 500" /> <Button x:Name="QueryButton" Content="Query" Margin="295,28,0,0" Click="QueryButton_Click" /> </Canvas>
- In the ContentGrid element in the XAML, after the Map element, define a Canvas to hold the task's input interface. Where possible, it is best to use a Canvas as the container element because Silverlight renders these most efficiently.
Creating an output interface for the Query task
To display the results of the Query task, you need to specify an output interface. In this example only the geometry of the results will be displayed. This is done by defining a GraphicsLayer within the Map element and a SimpleFillSymbol as a static resource.
Often you will want to also display information about the result. For simplicity in this code, that is not shown here. See the sample Query task application available in the Attribute Query sample in the Query section of the Interactive SDK for a more complete output interface.
- Add a reference to the System.Runtime.Serialization assembly to your project.
- Add an XML namespaces to the phone:PhoneApplicationPage element to map to the ESRI.ArcGIS.Client.Symbols namespaces in the ESRI.ArcGIS.Client assembly.
xmlns:esriSymbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;assembly=ESRI.ArcGIS.Client"
- Add a SimpleFillsSymbol as a resource by adding it to the LayoutRoot grid of your application. The symbol specified here is semi-transparent with a blue fill and outline. Later, you will apply this symbol to the task's results in the page's code-behind.
<Grid.Resources> <esriSymbols:SimpleFillSymbol x:Key="ResultsFillSymbol" Fill="#500000FF" BorderBrush="Blue" BorderThickness="1" /> </Grid.Resources>
- Add a GraphicsLayer to the Map control XAML element. Make sure it is placed below the map service layer in the XAML so that it is drawn above the map service layer at run time. For further information, see Adding layers.
<esri:Map x:Name="MyMap" Extent="-130, 20, -60, 40"> <esri:Map.Layers> <esri:ArcGISTiledMapServiceLayer ID="StreetMapLayer" Url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"> </esri:ArcGISTiledMapServiceLayer> <esri:GraphicsLayer ID="MyGraphicsLayer" > </esri:GraphicsLayer> </esri:Map.Layers> </esri:Map>
Implementing the Query task's execution logic
Now that you've specified the Query task's user interface, you need to define its execution logic. This execution logic can be divided into three parts:
You will implement these components in .NET code contained in the main page's code-behind. This code is linked to the XAML presentation layer by manipulating elements that you declared in XAML with "x:Name" or "ID" attributes and implementing methods that you declared in XAML as event handlers. The steps below assume that you are adding code to the MainPage class in the code-behind file for your Window Phone application's main page (e.g. MainPage.xaml.cs). In this example, C# is used.
Executing the task
To execute a Query task, you need to instantiate the task, specifying the layer that will be queried, wire the task's event handlers, initialize the task's query parameters, and call the task's execution method. The steps below will show you how to do this in the code-behind of your application's main page (e.g. MainPage.xaml.cs). The task is declared and initialized in the code-behind because tasks alone do not define any user interface, but rather encapsulate pieces of execution logic. In Silverlight, XAML is reserved for an application's presentation layer, while the code-behind is where business logic is implemented.
- In the code-behind of your application's main page, add a using statements for the ESRI.ArcGIS.Client namespace, the ESRI.ArcGIS.Client.Tasks namespace, and the ESRI.ArcGIS.Client.Symbols namespace.
using ESRI.ArcGIS.Client; using ESRI.ArcGIS.Client.Tasks; using ESRI.ArcGIS.Client.Symbols;
- Implement a handler for the QueryButton's click event. Recall that you declared this handler when you defined the QueryButton control in the page's XAML.
private void QueryButton_Click(object sender, RoutedEventArgs e) { }
- In the click handler, declare and instantiate a Query task. Set the server-side feature layer that the task will query by passing the layer's URL to the Query task's constructor. To find the URL, you can use the ArcGIS Services Directory or the MapIt Spatial Data Services Directory. See Discovering services for more information. This example uses the states layer in the ESRI_Census_USA ArcGIS Server service.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); }
- Specify a handler for the task's ExecuteCompleted event. The method specified will be called when the Query task is done executing. You will implement this handler in the Displaying Results section.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; }
- Specify a handler for the task's Failed event, which fires when there is a problem executing the task. You will define this handler in the Handling execution errors section.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; }
- Declare and instantiate a Query object. The Query object is used to define the execution parameters for Query tasks.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; Query query = new Query(); }
- Since you will draw the Query task's results on the map, specify that geometry be returned with the results.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; Query query = new Query(); query.ReturnGeometry = true; }
- Define the fields to return with the query results. Here you will specify that the query return the state name and population density fields so that you could use them in display of the results. In this case, we will not be displaying them, and returning them is shown for instructional purposes. In practice, only fields required by your application should be returned so that network traffic is minimized.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; Query query = new Query(); query.ReturnGeometry = true; query.OutFields.AddRange(new string[] { "STATE_NAME", "POP07_SQMI" }); }
- Specify the where clause for the query as the text contained in the QueryTextBox control. The where clause defines the conditions that features must satisfy to be returned in the query results.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; Query query = new Query(); query.ReturnGeometry = true; query.OutFields.AddRange(new string[] { "STATE_NAME", "POP07_SQMI" }); query.Where = QueryTextBox.Text; }
- Execute the query task with the parameters set on the Query object.
private void QueryButton_Click(object sender, RoutedEventArgs e) { QueryTask queryTask = new QueryTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" + "Demographics/ESRI_Census_USA/MapServer/5"); queryTask.ExecuteCompleted += QueryTask_ExecuteCompleted; queryTask.Failed += QueryTask_Failed; Query query = new Query(); query.ReturnGeometry = true; query.OutFields.AddRange(new string[] { "STATE_NAME", "POP07_SQMI" }); query.Where = QueryTextBox.Text; queryTask.ExecuteAsync(query); }
Displaying results
Once the Query task executes, the results, if any, need to be displayed on the map, and if no results the user needs that information returned. The steps below will show you how to do this in the code-behind of your application's main page (e.g. MainPage.xaml.cs).
- Declare a handler for the Query task's ExecuteCompleted event. This handler will be invoked when a query is complete. A FeatureSet containing the features that satisfy the query is passed to the handler's args parameter.
private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) { }
- Get a reference to the results GraphicsLayer and clear any previously added graphics from it.
private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) { GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); }
- Check whether any results satisfying the query were found.
private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) { GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (args.FeatureSet.Features.Count > 0) { } else { } }
- If results were found, loop through them. Apply the results fill symbol you declared in the page's XAML to each feature. Then add it to the results GraphicsLayer.
private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) { GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (args.FeatureSet.Features.Count > 0) { foreach (Graphic resultFeature in args.FeatureSet.Features) { resultFeature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as Symbol; graphicsLayer.Graphics.Add(resultFeature); } } else { } }
- If no features were found, notify the user with a MessageBox.
private void private void QueryTask_ExecuteCompleted(object sender, QueryEventArgs args) { GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (args.FeatureSet.Features.Count > 0) { foreach (Graphic resultFeature in args.FeatureSet.Features) { resultFeature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as Symbol; graphicsLayer.Graphics.Add(resultFeature); } } else { MessageBox.Show("No features found"); } }
Handling execution errors
Tasks do not always Execute as expected, and failures also need to be handled.
- Declare a handler for the Query task's Failed event. This handler will be invoked if there is a problem with executing a query.
private void QueryTask_Failed(object sender, TaskFailedEventArgs args) { }
Notify the user of the problem with a MessageBox.
private void QueryTask_Failed(object sender, TaskFailedEventArgs args) { MessageBox.Show("Query failed: " + args.Error); }