Identify task
The Identify task allows you to search the layers in a map for features that intersect an input geometry. Once the matching features are returned, you can use .NET code to display their geometries and attributes in your Windows Phone application. To use an Identify task, you need to include code to define the task's user interface (UI) and specify its execution logic.
A sample of an Identify task application is available in the Identify sample in the Query section of the Interactive SDK.
Creating an Identify 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 an Identify task:
- Creating an input interface for the Identify task
- Creating an output interface for the Identify task
- Implementing the Identify task's execution logic, including:
This application defines an Identify task that uses the Map control's Hold gesture for specifying the input geometry and executing the task. The list of intersecting features is displayed in a combination of a Button and a ListBox. The feature currently selected has its attributes shown in a ListBox below the Button.
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>
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 Identify task
Since tasks do not define a UI, you must implement an input interface to allow users of your application to perform identify operations. The interface defined by the example can be divided into the following three parts:
- Information about how to execute the task
- Specification of input geometry
- Display of the user-defined input
You'll define each of these in the following steps:
- In XAML after the Map's definition, specify a Border to use as the background for the task's instructions. The border's resizing behavior allows you to also use it as the background for the list of results and their attributes. Inside the border, use a Grid control to organize the instructions and results.
<Border x:Name="IdentifyBorder" Background="#99000000" BorderThickness="1" CornerRadius="5" BorderBrush="Gray" VerticalAlignment="Top" Margin="5" Padding="5"> <Grid x:Name="IdentifyGrid" HorizontalAlignment="Center" > <Grid.RowDefinitions> <RowDefinition Height="40" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> </Grid> </Border>
- Define a TextBlock to inform the user about how to execute the Identify task.
<Border x:Name="IdentifyBorder" Background="#99000000" BorderThickness="1" CornerRadius="5" BorderBrush="Gray" VerticalAlignment="Top" Margin="5" Padding="5"> <Grid x:Name="IdentifyGrid" HorizontalAlignment="Center" > <Grid.RowDefinitions> <RowDefinition Height="40" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="Tap and hold on the map to identify a feature" Foreground="White" FontSize="20" HorizontalAlignment="Center" /> </Grid> </Border>
- Use the map's Hold gesture to specify a point for the input geometry for the Identify task. This gesture fires whenever the Map control is touched and held without moving. Define the MapGesture attribute within the Map XAML element as shown in the following code. You will define the handler later in this topic.
<esri:Map x:Name="MyMap" Extent="-130, 20, -60, 40" MapGesture="MyMap_MapGesture" > <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>
- To show the user the location of the identify operation, display an image at the click point. Images can be displayed on a Map control by using a SimpleMarkerSymbol, which is included in the ESRI.ArcGIS.Client.Symbols namespace of the ESRI.ArcGIS.Client assembly. To use a SimpleMarkerSymbol in XAML, first add an XML namespace reference to the ESRI.ArcGIS.Client.Symbols namespace.
xmlns:esriSymbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;assembly=ESRI.ArcGIS.Client"
Note:You need to add a reference to the System.Runtime.Serialization assembly to your project to work with symbols.
- Declare a SimpleMarkerSymbol as a resource of the root Grid element.
<Grid.Resources> <esriSymbols:SimpleMarkerSymbol /> </Grid.Resources>
- Specify the x:Key attribute for the symbol. This allows you to reference the symbol from the page's code-behind.
<Grid.Resources> <esriSymbols:SimpleMarkerSymbol x:Key="IdentifyLocationSymbol" /> </Grid.Resources>
- Provide visual details so that the symbol is a small blue circle.
<Grid.Resources> <esriSymbols:SimpleMarkerSymbol x:Key="IdentifyLocationSymbol" Color="Blue" Size="15" /> </Grid.Resources>
- Add a GraphicsLayer to the Map control to use for drawing the symbol on the map.
<esri:Map x:Name="MyMap" Extent="-130, 20, -60, 40" MapGesture="MyMap_MapGesture" > <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="IdentifyIconGraphicsLayer" /> </esri:Map.Layers> </esri:Map>
- Similarly to the SimpleMarkerSymbol, add a SimpleFillSymbol to the root grid's resources.
<Grid.Resources> <esriSymbols:SimpleMarkerSymbol x:Key="IdentifyLocationSymbol" Color="Blue" Size="15" /> <esriSymbols:SimpleFillSymbol x:Key="SelectedFeatureSymbol" Fill="#64FF0000" BorderBrush="Red" BorderThickness="2" /> </Grid.Resources>
- Add a second GraphicsLayer to the Map control to use for highlighting the selected feature on the map.
<esri:Map x:Name="MyMap" Extent="-130, 20, -60, 40" MapGesture="MyMap_MapGesture" > <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="IdentifyIconGraphicsLayer" /> <esri:GraphicsLayer ID="ResultsGraphicsLayer" /> </esri:Map.Layers> </esri:Map>
Instructions are displayed so that the user of the application will know how to execute the Identify task and will be able to enter a point to identify.
Creating an output interface for the Identify task
To display the results of the Identify task, you need to specify an output interface. Since the result features of an identify operation will overlap geographically, this example shows how to implement a Button and ListBox combination that allows users to select a single feature to display, along with a ListBox to show the selected feature's attributes.
A Button and ListBox are used together since the ComboBox control is not supported on Windows Phone.
- The Border element you defined earlier as the background for the Identify task's instructions will also be used as the background for the Button and ListBox that display results. Inside the grid already defined in the border, add another Grid control to position the results information and control their visibility. In the Grid element, specify the x:Name attribute to
enable access from the page's code-behind. Define the Visibility
attribute as Collapsed so that the uninitialized Button and
ListBox are not visible.
<Border x:Name="IdentifyBorder" Background="#99000000" BorderThickness="1" CornerRadius="5" HorizontalAlignment="Center" BorderBrush="Gray" VerticalAlignment="Top" Margin="5"> <Grid x:Name="IdentifyGrid" HorizontalAlignment="Right" VerticalAlignment="Top" > <Grid.RowDefinitions> <RowDefinition Height="50" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="Tap and hold on the map to identify a feature" Foreground="White" FontSize="20" Margin="10,5,10,5" /> <Grid x:Name="IdentifyResultsPanel" Visibility="Collapsed" Grid.Row="1" > </Grid> </Grid> </Border>
- In the IdentifyResultsPanel Grid control, define rows and columns to use to organize the controls used to display the results.
<Grid x:Name="IdentifyResultsPanel" Visibility="Collapsed" Grid.Row="1" > <Grid.RowDefinitions> <RowDefinition Height="80" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> </Grid>
- In the IdentifyResultsPanel element, define the Button for displaying the ListBox for selecting result features, and place it in the first row and first column of the grid. The Button will also display the currently selected feature as its content through data binding. Declare a handler for the Button's Click event. Later in this topic, you'll implement this handler so that it shows the ListBox of features returned by the IdentifyTask.
<Grid x:Name="IdentifyResultsPanel" Visibility="Collapsed" Grid.Row="1" > <Grid.RowDefinitions> <RowDefinition Height="80" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <Button x:Name="IdentifyResultsButton" MinWidth="150" Grid.Row="0" Grid.Column="0" Foreground="White" Background="Black" Click="IdentifyResultsButton_Click" Content="{Binding ElementName=FeatureChoicesListBox, Path=SelectedItem.Content}"/> </Grid>
- In the results panel, include a Close button to hide the result information. Place it in the first row and second column of the grid. Declare a handler for its Click event, which you'll define in a later step.
<Grid x:Name="IdentifyResultsPanel" Visibility="Collapsed" Grid.Row="1" > <Grid.RowDefinitions> <RowDefinition Height="80" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <Button x:Name="IdentifyResultsButton" MinWidth="150" Grid.Row="0" Grid.Column="0" Foreground="White" Background="Black" Click="IdentifyResultsButton_Click" Content="{Binding ElementName=FeatureChoicesListBox, Path=SelectedItem.Content}"/> <Button x:Name="CloseResults" Content="X" Background="DarkRed" Grid.Row="0" Grid.Column="1" Click="CloseResults_Click" /> </Grid>
- To finish the results panel, include a ListBox in the second row, spanning both columns. It will host the attributes of the identify result selected for display. In the ArcGIS Runtime SDK for Windows Phone, result features are returned as Graphic objects, each of which defines its attributes as a Dictionary. In this attribute dictionary, each item's Key is the attribute name, and Value is the attribute value. Since data controls in Silverlight can be bound to properties of CLR types, you can show the field name in one column and attribute value in the other by explicitly binding to the Key and Value properties.
<Grid x:Name="IdentifyResultsPanel" Visibility="Collapsed" Grid.Row="1" > <Grid.RowDefinitions> <RowDefinition Height="80" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <Button x:Name="IdentifyResultsButton" MinWidth="150" Grid.Row="0" Grid.Column="0" Foreground="White" Background="Black" Click="IdentifyResultsButton_Click" Content="{Binding ElementName=FeatureChoicesListBox, Path=SelectedItem.Content}"/> <Button x:Name="CloseResults" Content="X" Background="DarkRed" Grid.Row="0" Grid.Column="1" Click="CloseResults_Click" /> <ListBox x:Name="DataListBox" Grid.Row="1" Grid.ColumnSpan="2"> <ListBox.ItemTemplate> <DataTemplate> <Grid Width="400"> <Grid.ColumnDefinitions> <ColumnDefinition Width="200" /> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> <TextBlock Width="200" Text="{Binding Key}" Grid.Column="0" FontSize="20" /> <TextBlock Width="200" Text="{Binding Value}" Grid.Column="1" TextWrapping="Wrap" FontSize="20" /> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid>
- To show the user a list of features that are returned by the IdentifyTask so that one can be selected for viewing attributes, display a ListBox that is in a ChildPage. The ChildPage is included in the ESRI.ArcGIS.Client.Toolkit.Primitives namespace of the ESRI.ArcGIS.Client.Toolkit assembly. Add a reference to the ESRI.ArcGIS.Toolkit assembly to your project.
- To use a ChildPage in XAML, add an XML namespace reference to the ESRI.ArcGIS.Client.Toolkit.Primitives namespace in the ESRI.ArcGIS.Client.Toolkit namespace.
xmlns:esriToolkitPrimitives="clr-namespace:ESRI.ArcGIS.Client.Toolkit.Primitives;assembly=ESRI.ArcGIS.Client.Toolkit"
- In the ContentPanel grid, define a ChildPage. This will be used to hold the ListBox for selecting a feature.
<esriToolkitPrimitives:ChildPage x:Name="FeatureChoicesPage" IsOpen="False" Padding="20"> </esriToolkitPrimitives:ChildPage>
- In the FeatureChoicesPage ChildPage, define a ListBox to use to select a feature from the IdentifyTask results. Declare a handler for the ListBox's SelectionChanged event. The SelectionChanged event fires when the item selected in the ListBox changes. Later in this topic, you'll implement this handler so that it updates the attributes shown in the ListBox of the IdentifyResultsPanel and the result feature drawn on the map, as well as the feature shown in the IdentifyResultsButton's display.
<esriToolkitPrimitives:ChildPage x:Name="FeatureChoicesPage" IsOpen="False" Padding="20"> <ListBox x:Name="FeatureChoicesListBox" FontSize="34" SelectionChanged="FeatureChoicesListBox_SelectionChanged"> </ListBox> </esriToolkitPrimitives:ChildPage>
The output interface can now display the identify results.
Implementing the Identify task's execution logic
Now that you've specified the Identify task's UI, you need to define its execution logic. The execution logic can be divided into the following three parts:
- Task execution
- Task results display
- Execution error handling
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 Page class in the code-behind file for your Windows Phone application's main page (for example, MainPage.xaml.cs). In this example, C# is used.
Executing the task
In the application's XAML, you declared the MyMap_MapGesture method as a handler for the map's gesture events. Now you'll implement this handler in the page's code-behind. When you're done, the handler will display an icon at the clicked location, instantiate the task and configure its input parameters, and execute the task.
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. In Windows Phone development, like Silverlight, XAML is reserved for an application's presentation layer, while the code-behind is where business logic is implemented.
- Include using statements for the ESRI.ArcGIS.Client, ESRI.ArcGIS.Client.Symbols, and ESRI.ArcGIS.Client.Tasks namespaces.
using ESRI.ArcGIS.Client; using ESRI.ArcGIS.Client.Symbols; using ESRI.ArcGIS.Client.Tasks;
- Declare variables in the MainPage class to use in the identify operation, including IdentifyTask and IdentifyParameters:
IdentifyTask identifyTask; IdentifyParameters identifyParameters;
- In the MainPage constructor, instantiate an Identify task. Set the map service that the task will search by passing the service's URL to the Identify 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.
public MainPage() { InitializeComponent(); identifyTask = new IdentifyTask("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 Identify task is done executing. You'll implement this handler in the Displaying results section.
public MainPage() { InitializeComponent(); identifyTask = new IdentifyTask("http://sampleserver1.arcgisonline.com/ArcGIS/" + "rest/services/Demographics/ESRI_Census_USA/MapServer"); identifyTask.ExecuteCompleted += IdentifyTask_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.
public MainPage() { InitializeComponent(); identifyTask = new IdentifyTask("http://sampleserver1.arcgisonline.com/ArcGIS/" + "rest/services/Demographics/ESRI_Census_USA/MapServer"); identifyTask.ExecuteCompleted += IdentifyTask_ExecuteCompleted; identifyTask.Failed += IdentifyTask_Failed; }
- Instantiate a new IdentifyParameters object. The IdentifyParameters object is used to specify the input for Identify tasks.
public MainPage() { InitializeComponent(); identifyTask = new IdentifyTask("http://sampleserver1.arcgisonline.com/ArcGIS/" + "rest/services/Demographics/ESRI_Census_USA/MapServer"); identifyTask.ExecuteCompleted += IdentifyTask_ExecuteCompleted; identifyTask.Failed += IdentifyTask_Failed; identifyParameters = new IdentifyParameters(); }
- Specify that all the map service's layers be searched. The
LayerOption parameter can also be set to search only the top-most
or visible layers.
public MainPage() { InitializeComponent(); identifyTask = new IdentifyTask("http://sampleserver1.arcgisonline.com/ArcGIS/" + "rest/services/Demographics/ESRI_Census_USA/MapServer"); identifyTask.ExecuteCompleted += IdentifyTask_ExecuteCompleted; identifyTask.Failed += IdentifyTask_Failed; identifyParameters = new IdentifyParameters(); identifyParameters.LayerOption = LayerOption.visible; }
- Declare the MyMap_MapGesture method.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { }
- Listen for Hold events, which will trigger Identify tasks.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { } }
- Retrieve the GraphicsLayer for the Identify icon and clear it of any previously drawn symbols.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); } }
- Instantiate a new Graphic. Set its geometry to be the point held on the map and its symbol to be the SimpleMarkerSymbol resource that references the Identify icon.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() { Geometry = e.MapPoint, Symbol = LayoutRoot.Resources["IdentifyLocationSymbol"] as SimpleMarkerSymbol }; } }
- Add the Identify graphic to the GraphicsLayer.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() { Geometry = e.MapPoint, Symbol = LayoutRoot.Resources["IdentifyLocationSymbol"] as SimpleMarkerSymbol }; graphicsLayer.Graphics.Add(graphic); } }
- Use the Map control's properties to initialize the map extent, width, and height of the Identify parameters.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() { Geometry = e.MapPoint, Symbol = LayoutRoot.Resources["IdentifyLocationSymbol"] as SimpleMarkerSymbol }; graphicsLayer.Graphics.Add(graphic); identifyParameters.MapExtent = MyMap.Extent; identifyParameters.Width = (int)MyMap.ActualWidth; identifyParameters.Height = (int)MyMap.ActualHeight; } }
- Set the search geometry for the Identify task to be the point clicked on the map.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() { Geometry = e.MapPoint, Symbol = LayoutRoot.Resources["IdentifyLocationSymbol"] as SimpleMarkerSymbol }; graphicsLayer.Graphics.Add(graphic); identifyParameters.MapExtent = MyMap.Extent; identifyParameters.Width = (int)MyMap.ActualWidth; identifyParameters.Height = (int)MyMap.ActualHeight; identifyParameters.Geometry = e.MapPoint; } }
- Execute the Identify task.
private void MyMap_MapGesture(object sender, ESRI.ArcGIS.Client.Map.MapGestureEventArgs e) { if (e.Gesture == ESRI.ArcGIS.Client.GestureType.Hold) { GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); ESRI.ArcGIS.Client.Graphic graphic = new ESRI.ArcGIS.Client.Graphic() { Geometry = e.MapPoint, Symbol = LayoutRoot.Resources["IdentifyLocationSymbol"] as SimpleMarkerSymbol }; graphicsLayer.Graphics.Add(graphic); identifyParameters.MapExtent = MyMap.Extent; identifyParameters.Width = (int)MyMap.ActualWidth; identifyParameters.Height = (int)MyMap.ActualHeight; identifyParameters.Geometry = e.MapPoint; identifyTask.ExecuteAsync(identifyParameters); } }
Displaying results
In the constructor for the MainPage class, you specified IdentifyTask_ExecuteCompleted as the handler for the task's ExecuteCompleted event. This event receives the Identify task's results, which consist of information about all the features in the specified search layers (all, visible, or top-most) that intersect the search geometry. In the main page's XAML, you also declared a ListBox in a ChildPage to hold the results features (paired with a Button to show it), a ListBox to display the selected feature's attributes, and a button to close the results information. On the IdentifyResultsButton, you specified the IdentifyResultsButton_Click method as the handler for the button's Click event. On the ListBox in the ChildPage you specified the FeatureChoicesListBox_SelectionChanged method as the handler for the ListBox's SelectionChanged event. On the Close button, you specified the CloseResults_Click method as the handler for the button's Click event.
In this section, you'll implement the ExecuteCompleted handler to populate the FeatureChoicesListBox with a list of the features' display values. Then, you'll implement the IdentifyResultsButton_Click method to show the ListBox of identified features. You will implement the FeatureChoicesListBox_SelectionChanged method to display the attributes of the selected feature in the ListBox of the IdentifyResultsPanel. Finally, you'll implement the CloseResults_Click method to close the identify results display.
- Declare a handler for the Identify task's ExecuteCompleted event. This handler will be invoked when an identify operation is complete. A list of IdentifyResults containing information about the features with geometries intersecting the search geometry is passed to the handler's args parameter. Each IdentifyResult contains the feature found, the name and ID of the layer containing the feature, the value of the feature's display field, and other information.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { }
- Remove previous results from the FeatureChoicesListBox, and check whether any results were found for the current operation.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { } else { } }
- If results were found, make the StackPanel containing the IdentifyResultsButton and results ListBox visible.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { IdentifyResultsPanel.Visibility = Visibility.Visible; } else { } }
- Loop through the result features. For each one, add its display value and layer to the FeatureChoicesListBox. Once each Identify result is processed, call the ListBox's UpdateLayout method to apply the updates.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { IdentifyResultsPanel.Visibility = Visibility.Visible; foreach (IdentifyResult result in args.IdentifyResults) { string title = string.Format("{0} ({1})", result.Value.ToString(), result.LayerName); ListBoxItem lbi = new ListBoxItem(); lbi.Background = new SolidColorBrush(Colors.Black); lbi.Foreground = new SolidColorBrush(Colors.White); lbi.Content = title; FeatureChoicesListBox.Items.Add(lbi); } FeatureChoicesListBox.UpdateLayout(); } else { } }
- At the top of the main page's class, declare an IdentifyResults member variable. This will be used to store the most recently returned set of task results for use when a new result is selected from the ListBox.
private List<IdentifyResult> _lastIdentifyResult;
- Store the Identify task's results in the member variable.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { IdentifyResultsPanel.Visibility = Visibility.Visible; foreach (IdentifyResult result in args.IdentifyResults) { string title = string.Format("{0} ({1})", result.Value.ToString(), result.LayerName); ListBoxItem lbi = new ListBoxItem(); lbi.Background = new SolidColorBrush(Colors.Black); lbi.Foreground = new SolidColorBrush(Colors.White); lbi.Content = title; FeatureChoicesListBox.Items.Add(lbi); } FeatureChoicesListBox.UpdateLayout(); _lastIdentifyResult = args.IdentifyResults; } else { } }
- Initialize the SelectedIndex of the FeatureChoicesListBox so that the first item in the list is selected. This will also fire the FeatureChoicesListBox's SelectionChanged event, which you'll implement to update the Identify results ListBox.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { IdentifyResultsPanel.Visibility = Visibility.Visible; foreach (IdentifyResult result in args.IdentifyResults) { string title = string.Format("{0} ({1})", result.Value.ToString(), result.LayerName); ListBoxItem lbi = new ListBoxItem(); lbi.Background = new SolidColorBrush(Colors.Black); lbi.Foreground = new SolidColorBrush(Colors.White); lbi.Content = title; FeatureChoicesListBox.Items.Add(lbi); } FeatureChoicesListBox.UpdateLayout(); _lastIdentifyResult = args.IdentifyResults; FeatureChoicesListBox.SelectedIndex = 0; } else { } }
- If no features were found, hide the Grid containing the Identify Button and ListBox. Notify the user with a MessageBox.
private void IdentifyTask_ExecuteCompleted(object sender, IdentifyEventArgs args) { FeatureChoicesListBox.Items.Clear(); if (args.IdentifyResults.Count > 0) { IdentifyResultsPanel.Visibility = Visibility.Visible; foreach (IdentifyResult result in args.IdentifyResults) { string title = string.Format("{0} ({1})", result.Value.ToString(), result.LayerName); ListBoxItem lbi = new ListBoxItem(); lbi.Background = new SolidColorBrush(Colors.Black); lbi.Foreground = new SolidColorBrush(Colors.White); lbi.Content = title; FeatureChoicesListBox.Items.Add(lbi); } FeatureChoicesListBox.UpdateLayout(); _lastIdentifyResult = args.IdentifyResults; FeatureChoicesListBox.SelectedIndex = 0; } else { IdentifyResultsPanel.Visibility = Visibility.Collapsed; MessageBox.Show("No features found"); } }
- Declare the IdentifyResultsButton_Click method. In the page's XAML, you specified this method as the handler for the IdentifyResultsButton's Click event. The Click event fires whenever the button is clicked.
private void IdentifyResultsButton_Click(object sender, RoutedEventArgs e) { }
- When the IdentifyResultsButton is clicked, show the ChildPage containing the ListBox of features returned by the IdentifyTask.
private void IdentifyResultsButton_Click(object sender, RoutedEventArgs e) { FeatureChoicesPage.IsOpen = true; }
- Declare the FeatureChoicesListBox_SelectionChanged method. In the page's XAML, you specified this method as the handler for the FeatureChoicesListBox's SelectionChanged event. The SelectionChanged event fires whenever the selected item in the ListBox is changed. This includes both interactive and programmatic changes to the selected item, even when the selection is not valid (for example, when the ListBox is cleared).
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { }
- Retrieve the GraphicsLayer for displaying the currently selected feature, and clear it of any previously displayed results.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); }
- Check whether an item is currently selected. If no item is selected, the ListBox's SelectedIndex will be -1.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (FeatureChoicesListBox.SelectedIndex > -1) { } }
- If an item is selected, get the Graphic (that is, feature) corresponding to that item. For this, the LastResult property on the Identify task is useful. This property holds the set of results returned by the most recently executed identify operation.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (FeatureChoicesListBox.SelectedIndex > -1) { Graphic selectedFeature = _lastIdentifyResult[FeatureChoicesListBox.SelectedIndex].Feature; } }
- Update the Identify ListBox to show the attributes of the selected feature. In the page's XAML, you specified a Grid with two columns in the ListBox, each containing a TextBox, and that the TextBoxes be bound to properties called Key and Value. A Graphic object keeps its attribute in a Dictionary, which is a list of key/value pairs—each item defines Key and Value properties. You can bind the ListBox to the selected Graphic (feature) by passing the Attributes Dictionary to the ListBox's ItemsSource property.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (FeatureChoicesListBox.SelectedIndex > -1) { Graphic selectedFeature = _lastIdentifyResult[FeatureChoicesListBox.SelectedIndex].Feature; DataListBox.ItemsSource = selectedFeature.Attributes; } }
- Apply the fill symbol you defined in the page's XAML to the selected feature, and add the feature to the ResultsGraphicsLayer.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (FeatureChoicesListBox.SelectedIndex > -1) { Graphic selectedFeature = _lastIdentifyResult[FeatureChoicesListBox.SelectedIndex].Feature; DataListBox.ItemsSource = selectedFeature.Attributes; selectedFeature.Symbol = LayoutRoot.Resources["SelectedFeatureSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol; graphicsLayer.Graphics.Add(selectedFeature); } }
- Close the FeatureChoicesPage once a selection has been made.
void FeatureChoicesListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { GraphicsLayer graphicsLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); if (FeatureChoicesListBox.SelectedIndex > -1) { Graphic selectedFeature = _lastIdentifyResult[FeatureChoicesListBox.SelectedIndex].Feature; DataListBox.ItemsSource = selectedFeature.Attributes; selectedFeature.Symbol = LayoutRoot.Resources["SelectedFeatureSymbol"] as ESRI.ArcGIS.Client.Symbols.Symbol; graphicsLayer.Graphics.Add(selectedFeature); FeatureChoicesPage.IsOpen = false; } }
- Implement the Click event for the button to close the identify results display.
private void CloseResults_Click(object sender, RoutedEventArgs e) { }
- Close the identify results display by setting its visibility to collapsed.
private void CloseResults_Click(object sender, RoutedEventArgs e) { IdentifyResultsPanel.Visibility = Visibility.Collapsed; }
- Clear the graphic marking the point held on the map.
private void CloseResults_Click(object sender, RoutedEventArgs e) { IdentifyResultsPanel.Visibility = Visibility.Collapsed; GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); }
- Clear the graphic marking the selected feature on the map.
private void CloseResults_Click(object sender, RoutedEventArgs e) { IdentifyResultsPanel.Visibility = Visibility.Collapsed; GraphicsLayer graphicsLayer = MyMap.Layers["IdentifyIconGraphicsLayer"] as GraphicsLayer; graphicsLayer.ClearGraphics(); GraphicsLayer selectedLayer = MyMap.Layers["ResultsGraphicsLayer"] as GraphicsLayer; selectedLayer.ClearGraphics(); }
Handling execution errors
The final step in implementing the Identify task is handling errors when the task is executed and fails. In the constructor of the MainPage class, you specified IdentifyTask_ExecuteCompleted as the handler for the task's ExecuteCompleted event. This event receives the Identify task's failure information, which can be passed to the user of the application.
- Declare a handler for the Identify task's Failed event. This handler will be invoked if there is a problem with executing an identify operation.
private void IdentifyTask_Failed(object sender, TaskFailedEventArgs args) { }
- Notify the user of the problem with a MessageBox.
private void IdentifyTask_Failed(object sender, TaskFailedEventArgs args) { MessageBox.Show("Identify failed: " + args.Error); }