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 ArcGIS Runtime SDK for Windows Phone application. To use a Find task, you need to include code to define its user interface (UI) and specify its execution logic.
An example 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 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:
- Creating an input interface for the Find task
- Creating an output interface for the Find task
- Implementing the Find task's execution logic
This application defines a Find task that uses a TextBox control to specify the input value and a Button to execute 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>
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 Find task
Since tasks do not define UIs, you need to implement an interface for the Find task's input to allow users of your application to execute find operations. The following example includes a TextBox for defining the input value and a Button to execute the task.
- 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="330" > </Canvas>
- 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="330" > <Rectangle Fill="#CC5C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Width="310" 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="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>
- 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>
- 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>
- 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>
- Specify a handler for the Button's Click event. Later in this topic, you'll 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.
You can also display information about the result; however, 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.
- Add a reference to the System.Runtime.Serialization assembly to your project.
- Add an XML namespace reference to the phone:PhoneApplicationPage element to map to the ESRI.ArcGIS.Client.Symbols namespace in the ESRI.ArcGIS.Client assembly.
xmlns:esriSymbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;assembly=ESRI.ArcGIS.Client"
- Add a SimpleFillSymbol as a resource by adding it to the LayoutRoot grid of your application. The symbol specified here is semitransparent with a red 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="#64FF0000" BorderBrush="Red" BorderThickness="2" /> </Grid.Resources>
- 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 Find task's execution logic
Now that you've specified the Find 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 steps 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 Find task, you need to instantiate the task, specifying the map service that will be searched, then wire the task's event handlers, initialize the task's search parameters, and call the task's execution method. The following steps show you 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.
- 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;
- Implement a handler for the FindButton's click event. You declared this handler when you defined the FindButton control in the page's XAML.
private void FindButton_Click(object sender, RoutedEventArgs e) { }
- 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/"); }
- Specify a handler for the task's ExecuteCompleted event. The method specified will be called when the Find task is done executing. You'll 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; }
- 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 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; }
- 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(); }
- 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 }); }
- 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" }); }
- Since you'll 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; }
- 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; }
- 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. 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).
- 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) { }
- 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(); }
- 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 { } }
- 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 { } }
- 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.
- 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) { }
Notify the user of the problem with a MessageBox.
private void FindTask_Failed(object sender, TaskFailedEventArgs args) { MessageBox.Show("Find failed: " + args.Error); }