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 need to include code to define its user interface (UI) and specify its execution logic.

Samples of Query tasks are available in the Query section of the Interactive SDK.

Creating a Query task

The following sections walk you through building an example of XAML and .NET code (in this case C#) for a simple Windows Phone application that includes a Query task:

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 ContentPanel in MainPage.xaml should look like the following code:

<Grid x:Name="ContentPanel" 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>

NoteNote:

In the following example code, the Extent of the Map was changed to -130, 20, -60, 40 to display the entire 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 a UI, you must implement an input interface for the Query task to allow users of your application to execute queries. To accomplish this, the example includes a TextBox for defining the query and a Button to execute the task.

  1. In the ContentPanel element in the XAML, after the Map element, define a Canvas to hold the task's input interface. Where possible, it's 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>
    
  2. Specify a Rectangle to use as the background for the input interface. This rectangle will be semitransparent 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>
    
  3. 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>
    
  4. 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>
    
  5. 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>
    
  6. 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>
    
  7. Specify a handler for the Button's Click event. Later in this topic, you'll 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>
    

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.

NoteNote:

You can also display information about the result; however, 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.

  1. Add a reference to the System.Runtime.Serialization assembly to your project.
  2. 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"
    
  3. Add a SimpleFillsSymbol as a resource by adding it to the LayoutRoot grid of your application. The symbol specified here is semitransparent with a blue fill and outline. Later in this topic, you'll 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>
    
  4. Add a GraphicsLayer to the Map control XAML element. Make sure it's placed below the map service layer in the XAML so that it's 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 UI, you need to define its execution logic. The execution logic can be divided into the following three parts:

You'll 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 following sections assume that you are adding code to the MainPage class in the code-behind file for your Window Phone application's main page (for example, MainPage.xaml.cs). In this example, C# is used.

Executing the task

To execute a Query task, you need to instantiate the task, specify 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 following steps show how to do this in the code-behind of your application's main page (for example, MainPage.xaml.cs). The task is declared and initialized in the code-behind because tasks alone do not define any UI, but rather encapsulate pieces of execution logic. XAML is reserved for an application's presentation layer, while the code-behind is where business logic is implemented.

  1. In the code-behind of your application's main page, add using statements for the ESRI.ArcGIS.Client, ESRI.ArcGIS.Client.Tasks, and ESRI.ArcGIS.Client.Symbols namespaces.
    using ESRI.ArcGIS.Client;
    using ESRI.ArcGIS.Client.Tasks;
    using ESRI.ArcGIS.Client.Symbols;
    
  2. Implement a handler for the QueryButton's click event. You declared this handler when you defined the QueryButton control in the page's XAML.
    private void QueryButton_Click(object sender, RoutedEventArgs e)
    {
    }
    
  3. 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");
    }
    
  4. Specify a handler for the task's ExecuteCompleted event. The method specified will be called when the Query task is done executing. You'll 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;
    }
    
  5. Specify a handler for the task's Failed event, which fires when there is a problem executing the task. You'll 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;
    }
    
  6. 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();
    }
    
  7. Since you'll 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;
    }
    
  8. Define the fields to return with the query results. Here you'll specify that the query return the state name and population density fields.
    NoteNote:

    You can display these fields in the results; however, that process is not shown here, and returning them is shown for instructional purposes only.

    TipTip:

    To minimize network traffic, return only those fields required by your application.

    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" });
    }
    
  9. 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;
    }
    
  10. 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. If no results are returned, the user needs to be notified. The following steps show you how to do this in the code-behind of your application's main page (for example, MainPage.xaml.cs):

  1. 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)
    {
    }
    
  2. 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();
    }
    
  3. 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
        {
        }
    }
    
  4. 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
        {
        }
    }
    
  5. 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.

  1. 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)
    {
    }
    
  2. Notify the user of the problem with a MessageBox.

    private void QueryTask_Failed(object sender, TaskFailedEventArgs args)
    {
        MessageBox.Show("Query failed: " + args.Error);
    }
    

1/23/2012