Find task

The Find task allows you to search one or more layers in a map for features with attribute values that match or contain an input value. Once the matching features are returned, you can use .NET code to display their geometries and attributes in your Windows Phone application. To use a Find task, you will need to include code to define its user interface and specify its execution logic.

A sample of a Find task application is available in the Find sample in the Query section of the Interactive SDK.

Creating a Find task

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

  1. Creating an input interface for the Find task
  2. Creating an output interface for the Find task
  3. Implementing the Find task's execution logic, including:
    1. Executing the task
    2. Displaying results
    3. Handling execution errors

This application defines a Find task that uses a TextBox control for specifying the input value 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>

NoteNote:

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 Find task

Since tasks do not define user interfaces, you need to implement an interface for the Find task's input to allow your application's users to execute find operations. For this, the example simply includes a TextBox for defining the input value and a Button to execute the task.

  1. 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="330" >
    </Canvas>
    
  2. 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="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Width="310" 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="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="310" Height="100" />
        <TextBlock Text="Find counties with names containing:" Foreground="White" FontSize="22" Margin="8,5,0,0" />
    </Canvas>
    
  4. Define a TextBox for specifying the task's input value.
    <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Width="310" Height="100" />
        <TextBlock Text="Find counties with names containing:" Foreground="White" FontSize="22" Margin="8,5,0,0" />
        <TextBox x:Name="FindTextBox" Width="200" Margin="15,32,0,0" />
    </Canvas>
    
  5. Add a default value to the TextBox.
    <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Width="310" Height="100" />
        <TextBlock Text="Find counties with names containing:" Foreground="White" FontSize="22" Margin="8,5,0,0" />
        <TextBox x:Name="FindTextBox" Width="200" Margin="15,32,0,0" Text="Wash" />
    </Canvas>
    
  6. Add a Button to execute the task.
    <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Width="310" Height="100" />
        <TextBlock Text="Find counties with names containing:" Foreground="White" FontSize="22" Margin="8,5,0,0" />
        <TextBox x:Name="FindTextBox" Width="200" Margin="15,32,0,0" Text="Wash" />
        <Button x:Name="FindButton" Content="Find" Margin="205,32,0,0" />
    </Canvas>
    
  7. Specify a handler for the Button's Click event. Later, you will implement this handler so that it executes the Find task.
    <Canvas HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,15,7,0" Width="330" >
        <Rectangle Fill="#CC5C90B2" Stroke="Gray"  RadiusX="10" RadiusY="10" Width="310" Height="100" />
        <TextBlock Text="Find counties with names containing:" Foreground="White" FontSize="22" Margin="8,5,0,0" />
        <TextBox x:Name="FindTextBox" Width="200" Margin="15,32,0,0" Text="Wash" />
        <Button x:Name="FindButton" Content="Find" Margin="205,32,0,0" Click="FindButton_Click" />
    </Canvas>
    

Creating an output interface for the Find task

To display the results of the Find 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 Find task application available in the Find 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 SimpleFillSymbol as a resource by adding it to the LayoutRoot grid of your application. The symbol specified here is semi-transparent with a red 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="#64FF0000" BorderBrush="Red" BorderThickness="2" />
    </Grid.Resources>
    
  4. 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 Find task's execution logic

Now that you've specified the Find 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 Find task, you need to instantiate the task, specifying the map service that will be searched, wire the task's event handlers, initialize the task's search 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.

  1. 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;
    
  2. Implement a handler for the FindButton's click event. Recall that you declared this handler when you defined the FindButton control in the page's XAML.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
    }
    
  3. In the click handler, declare and instantiate a Find task. Set the map service layer that the task will search by passing the layer's URL to the Find task's constructor. To find the URL, you can use the ArcGIS Services Directory. See Discovering services for more information. This example uses the states layer of the ESRI_Census_USA service.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
    }
    
  4. Specify a handler for the task's ExecuteCompleted event. The method specified will be called when the Find task is done executing. You will implement this handler in the Displaying results section.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
    }
    
  5. 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 FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    }
    
  6. Declare and instantiate a FindParameters object. The FindParameters object is used to define the execution parameters for Find tasks.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
    }
    
  7. On the FindParameters object, set the layer to be searched by adding a layer ID of 3 to the LayerIds property. This corresponds to the counties layer.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
        findParameters.LayerIds.AddRange(new int[] { 3 });
    }
    
  8. Specify that the NAME field be searched in the find operation.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
        findParameters.LayerIds.AddRange(new int[] { 3 });
        findParameters.SearchFields.AddRange(new string[] { "NAME" });
    }
    
  9. Since you will draw the Find task's results on the map, specify that geometry be returned with the results.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
        findParameters.LayerIds.AddRange(new int[] { 3 });
        findParameters.SearchFields.AddRange(new string[] { "NAME" });
        findParameters.ReturnGeometry = true;
    }
    
  10. Define the value to search for as the text in the FindTextBox control.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
        findParameters.LayerIds.AddRange(new int[] { 3 });
        findParameters.SearchFields.AddRange(new string[] { "NAME" });
        findParameters.ReturnGeometry = true;
    
        findParameters.SearchText = FindTextBox.Text;
    }
    
  11. Execute the find task with the parameters specified by the FindParameters member variable.
    private void FindButton_Click(object sender, RoutedEventArgs e)
    {
        FindTask findTask = new FindTask("http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
                                         "Demographics/ESRI_Census_USA/MapServer/");
        findTask.ExecuteCompleted += FindTask_ExecuteCompleted;
        findTask.Failed += FindTask_Failed;
    
        FindParameters findParameters = new FindParameters();
        findParameters.LayerIds.AddRange(new int[] { 3 });
        findParameters.SearchFields.AddRange(new string[] { "NAME" });
        findParameters.ReturnGeometry = true;
    
        findParameters.SearchText = FindTextBox.Text;
    
        findTask.ExecuteAsync(findParameters);
    }
    

Displaying results

Once the Find 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).

  1. Declare a handler for the Find task's ExecuteCompleted event. This handler will be invoked when a find operation is complete. A list of FindResults containing information about the features with matching attributes is passed to the handler's args parameter. Each FindResult contains the feature found, the name and ID of the layer containing the feature, the name of the field containing the matching value, and other information.
    private void FindTask_ExecuteCompleted(object sender, FindEventArgs args)
    {
    }
    
  2. Get a reference to the results GraphicsLayer and clear any previously added graphics from it.
    private void FindTask_ExecuteCompleted(object sender, FindEventArgs args)
    {
        GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
        graphicsLayer.ClearGraphics();
    }
    
  3. Check whether any results were found.
    private void FindTask_ExecuteCompleted(object sender, FindEventArgs args)
    {
        GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
        graphicsLayer.ClearGraphics(); 
    
        if (args.FindResults.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 FindTask_ExecuteCompleted(object sender, FindEventArgs args)
    {
        GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
        graphicsLayer.ClearGraphics(); 
    
        if (args.FindResults.Count > 0)
        {
            foreach (FindResult result in args.FindResults)
            {
                result.Feature.Symbol = LayoutRoot.Resources["ResultsFillSymbol"] as Symbol;
                graphicsLayer.Graphics.Add(result.Feature);
            }
        }
        else
        {
        }
    }
    
  5. If no features were found, notify the user with a MessageBox.
    private void FindTask_ExecuteCompleted(object sender, FindEventArgs args)
    {
        GraphicsLayer graphicsLayer = MyMap.Layers["MyGraphicsLayer"] as GraphicsLayer;
        graphicsLayer.ClearGraphics(); 
    
        if (args.FindResults.Count > 0)
        {
            foreach (FindResult result in args.FindResults)
            {
                result.Feature.Symbol = ResultsFillSymbol;
                graphicsLayer.Graphics.Add(result.Feature);
            }
        }
        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 Find task's Failed event. This handler will be invoked if there is a problem with executing a find operation.
    private void FindTask_Failed(object sender, TaskFailedEventArgs args)
    {
    }
    
  2. Notify the user of the problem with a MessageBox.

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


12/1/2010