Identify features

Maps often combine many sources of information such as feature layers, image layers, and graphics. Labels and legends don't always provide enough information to work out what the map is displaying. Use the identify methods to quickly answer the question 'what is this item here?', allowing your users to easily explore and learn about the map content by tapping or clicking on them. Information returned can be shown in pop-ups or other UI components in your app.

You can identify the visible items at a specific point on screen:

  • Within all the layers in the map or only within a specific layer
  • Within all the graphics overlays in the view or only within a specific graphics overlay
  • Returning only the topmost item or all the items at that location
  • Returning the feature, graphic, or other item at that location, or by returning pop-ups for pop-up-enabled layers

Identify methods are asynchronous, so that the UI thread of your application is not blocked waiting for results. This is especially important when working with data with resides on a server, as results do not return immediately. The results of an identify take into account:

  • Symbology—tapping on a large marker symbol used to draw a point, or a wide line symbol used to draw a polyline or outline of a polygon will include those items in the results; it's not just the geometry that is used.
  • Visibility—the visibility of a graphics overlay or layer, and of an individual feature or graphic is checked, and results will only include the visible items. The opacity of a layer or graphic is ignored.
  • Visible extent—only items within the currently visible map extent are included in identify results.

Identify is supported on feature layers, map image layers, Web Map Service (WMS) layers, graphics overlays, and also on tiled layers that are based on map services that support identify.

Note:

If time-based filtering is being used (a time extent has been set on the displaying map or scene view), identify will only return features that are within the time extent set on the geo view.

The sections below show you how to identify different items in the map in different ways, but these approaches can be combined to provide general identify functionality if required.

Identify features in a feature layer

The steps below show you how to identify the features within a specific feature layer in the map. Later in this topic, these steps are adapted to identify only the topmost feature, identify against multiple layers, different types of layers, and to identify graphics.

  1. Listen to a tap or click event on the map or scene view, and get the point representing the center of the tap or click.
    // handle the tap event on the map view (or scene view)
    MyMapView.GeoViewTapped += async (s, e) =>
    {
        // get the tap location in screen units
        System.Windows.Point tapScreenPoint = e.Position;
    
    
        // ... code here to identify using the tap point ...
    };
  2. Call the required identify method, passing in the screen point from the previous step.
    1. Choose either to identify against a specific layer, or to identify against all layers.
    2. Specify a tolerance for the search radius of the identify operation. A tolerance of 0 identifies only items at the single pixel at the screen point. However, typically this level of precision is hard to achieve, so you can supply a tolerance around the screen point. A suitable tolerance for a tap operation on a touch screen should be equivalent to the size of the tip of a finger, and a smaller tolerance should be considered for mouse pointers.
    3. Specify whether to include pop-up information on the geo-elements returned. (If no pop-ups are defined for a layer or graphics overlay, pop-ups will not be included in the results regardless of this parameter value).
    4. Optionally, specify the maximum number of results per-layer to return. This may be especially useful if identifying on service layers, as you can limit the amount of information returned to the client (the maximum results will also be limited by the server).

    var layer = MyMapView.Map.OperationalLayers[0];
    var pixelTolerance = 20;
    var returnPopupsOnly = false;
    var maxResults = 5;
    
    
    // identify a layer using MapView, passing in the layer, the tap point, tolerance, types to return, and max results
    IdentifyLayerResult idResults = await MyMapView.IdentifyLayerAsync(layer, tapScreenPoint, pixelTolerance, returnPopupsOnly, maxResults);

  3. Results consist of layer content information about the layer the results are from, and a list of GeoElement. Each GeoElement represents a feature identified at the given screen point. Iterate the results, access the geometry and attributes of the identified features, and use them as required. In the example below, each identified feature is selected.

    // get the layer identified and cast it to FeatureLayer
    FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;
    
    
    // iterate each identified GeoElement in the results
    foreach (GeoElement idElement in idResults.GeoElements)
    {
        // cast the result GeoElement to Feature
        Feature idFeature = idElement as Feature;
    
    
        // select this feature in the feature layer
        idLayer.SelectFeature(idFeature);
    }

    Tip:

    Features are loadable, but when using identify methods, they are always returned already loaded.

Identify features in all feature layers

When you do not know which specific layer to identify on, you can identify items in any layer in the map. Change the first workflow above so that you do not specify the layer to identify. This time, the results are returned as a list of IdentifyLayerResult instead of a single result.

In the following example the results are iterated to select identified features from all layers in the result list.

// get the tap location in screen units
System.Windows.Point tapScreenPoint = e.Position;


var pixelTolerance = 20;
var returnPopupsOnly = false;
var maxLayerResults = 5;


// identify all layers in the MapView, passing the tap point, tolerance, types to return, and max results
IReadOnlyList<IdentifyLayerResult> idLayerResults = await MyMapView.IdentifyLayersAsync(tapScreenPoint, pixelTolerance, returnPopupsOnly, maxLayerResults);


// iterate the results for each layer
foreach (IdentifyLayerResult idResults in idLayerResults)
{
    // get the layer identified and cast it to FeatureLayer
    FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;


    // iterate each identified GeoElement in the results for this layer
    foreach (GeoElement idElement in idResults.GeoElements)
    {
        // cast the result GeoElement to Feature
        Feature idFeature = idElement as Feature;


        // select this feature in the feature layer
        idLayer.SelectFeature(idFeature);
    }
}

Layers that do not support identify or do not have any results based on the inputs are not included in the returned list.

Identify topmost item only

To identify only the topmost item at the screen point (or the topmost item per layer, if identifying against all layers) change the first workflow above by removing the maximum number of results parameter. GeoElements are still returned as a list, but the list will have only zero or one items.

The following code selects only the topmost feature identified at the screen point, for all feature layers in the map.

// get the tap location in screen units
System.Windows.Point tapScreenPoint = e.Position;


var pixelTolerance = 20;
var returnPopupsOnly = false;


// identify the topmost feature for all layers, passing in the tap point, tolerance, and types to return
IReadOnlyList<IdentifyLayerResult> idLayerResults = await MyMapView.IdentifyLayersAsync(tapScreenPoint, pixelTolerance, returnPopupsOnly);


// iterate the results for each layer
foreach (IdentifyLayerResult idResults in idLayerResults)
{
    // get the layer identified and cast it to FeatureLayer
    FeatureLayer idLayer = idResults.LayerContent as FeatureLayer;


    // see if a result was found for this layer (will be 0 or 1 result for each layer)
    if (idResults.GeoElements.Count == 1)
    {
        // cast the result GeoElement to Feature
        Feature idFeature = idResults.GeoElements[0] as Feature;


        // select this feature in the feature layer
        idLayer.SelectFeature(idFeature);
    }
}

Identify on map image layers

Identifying against map image layers and tiled map layers follows the same workflow as shown for feature layers. The difference when identifying against map image layers are:

  • Results are returned as Features; unlike other features however, they will not have a reference to a FeatureTable.
  • Map image layers may have one or more sublayers—identify results from map image layers reflect this structure, and return results for each sublayer separately. (Note that if you have specified a maximum number of results to return, this value applies per sublayer.)

The following code processes identify results for feature layers and map image layers. A recursive function is used to iterate through sublayer results for map image layers.

private void ProcessIdentifyResults(IReadOnlyList<IdentifyLayerResult> idLayerResults)
{
    // iterate the results for each layer
    foreach (IdentifyLayerResult idResults in idLayerResults)
    {
        // get the layer identified and try to cast it to FeatureLayer
        FeatureLayer featLayer = idResults.LayerContent as FeatureLayer;


        // process feature layer results
        if (featLayer != null)
        {
            // iterate each identified GeoElement in the results for this layer
            foreach (GeoElement idElement in idResults.GeoElements)
            {
                // cast the result GeoElement to Feature
                Feature idFeature = idElement as Feature;


                // select this feature in the feature layer
                featLayer.SelectFeature(idFeature);
            }
        }


        // if not a feature layer, check for map image layer
        if (idResults.LayerContent is ArcGISMapImageLayer || idResults.LayerContent is ArcGISMapImageSublayer)
        {
            // iterate each identified GeoElement in the results
            foreach (GeoElement idElement in idResults.GeoElements)
            {
                // cast the result GeoElement to Feature
                Feature idFeature = idElement as Feature;


                // can get the geometry and attributes, but FeatureTable will be null
                Geometry featureShape = idFeature.Geometry;
                IDictionary<string, object> featureAttrs = idFeature.Attributes;


                // ... code to display the GeoElement attributes here ...


            }


            // see if there are sublayer results, call this function again and pass them in
            ProcessIdentifyResults(idResults.SublayerResults);
        }
    }                      
}

Return pop-ups as results

Some types of layer support pop-ups. You can use an identify method to return pop-ups for map content at a screen point.

The following code provides an example of getting a popup from the identify results.

// identify all layers in the MapView, passing the tap point, tolerance, types to return, and max results
IReadOnlyList<IdentifyLayerResult> idLayerResults = await MyMapView.IdentifyLayersAsync(tapScreenPoint, pixelTolerance, returnPopupsOnly, maxLayerResults);
 if (idLayerResults.Count > 0)
{
    // get the first identify result
    IdentifyLayerResult firstIdLayerResult = idLayerResults.FirstOrDefault();


    if (firstIdLayerResult.Popups.Count > 0)
    {
        // get the first popup from the result
        Popup firstPopup = firstIdLayerResult.Popups.FirstOrDefault();


        // ... code here to show popup ...
    }
}

Identify features in a WMS layer

WMS layers differ from other layers as they do not support returning individual attributes or geometry for a feature. WMS services perform identification on the server and return HTML documents describing identified features. You can access the returned HTML document string through the "HTML" entry in the feature's attributes. This HTML string is suitable for display in a web view.

It is impossible to get the geometry for an identified (or any other) WMS feature. An identified WMS feature's geometry will always be null. Consequently, WMS layers do not support feature selection/highlight.

// Perform the identify operation on the WMS layer
IdentifyLayerResult myIdentifyResult = await MyMapView.IdentifyLayerAsync(myWmsLayer, e.Position, 20, false);

// Return if there's no feature to show
if (myIdentifyResult.GeoElements.Count() < 1) { return; }

// Retrieve the identified feature, which is always a WmsFeature for WMS layers
WmsFeature identifiedFeature = (WmsFeature)myIdentifyResult.GeoElements[0];

// Retrieve the WmsFeature's HTML content
string htmlContent = identifiedFeature.Attributes["HTML"].ToString();

Identify graphics

Graphics are identified using methods different than those used for layers. You can choose to return graphics in a specific graphic overlay or for all graphics overlays; you can also limit results to only the topmost graphic in each graphics overlay.

The following code identifies all graphics overlays in the map view, then loops through all graphics and selects them.

// identify all graphics overlays in the MapView, passing the tap point, tolerance, types to return, and max results
IReadOnlyList<IdentifyGraphicsOverlayResult> idGraphicOverlayResults = await MyMapView.IdentifyGraphicsOverlaysAsync(tapScreenPoint, pixelTolerance, returnPopupsOnly, maxLayerResults);


// iterate each graphics overlay
foreach(IdentifyGraphicsOverlayResult idGraphicResult in idGraphicOverlayResults)
{
    // iterate all graphics in the overlay and select them
    foreach(Graphic g in idGraphicResult.Graphics)
    {
        g.IsSelected = true;
    }
}