IdentifyTask

Imagine for a moment that you have multiple layers in your map or scene, and you want to click on a particular location and find everything at that location. See the following image:

IdentifyTask

If you click on these layers, the IdentifyTask object will return every feature in every layer that is located where you clicked. The IdentifyTask class uses the concept of a hit test. A hit test simply means that if the point where the user clicks intersects with any feature in any layer, those features are returned to IdentifyTask. It's possible to perform an Identify operation on both online and offline data. Let's look at an online example first, and then explore this further with the same kind of operation but with offline data.

All examples in this section are in the code provided with this book, which is called Chapter7a.

The online Identify task

Let's add some code, and then discuss how IdentifyTask works using an online service:

  1. In your project, open the MapViewBehavior.cs file and add the following using statement: using Esri.ArcGISRuntime.Tasks.Query;. Then, add a new event to the OnAttached method, as shown here:
    AssociatedObject.MouseUp += AssociatedObject_MouseUp; 
  2. In the event handler, add the following code:
    async void AssociatedObject_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        MapView mapView = sender as MapView;
        var screenPoint = e.GetPosition(mapView);
    
        // Convert the screen point to a point in map coordinates
        var mapPoint = mapView.ScreenToLocation(screenPoint);
    
        // Create a new IdentifyTask pointing to the map service to 
        // identify (USA)
        var uri = new Uri("http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer");
        var identifyTask = new IdentifyTask(uri);
    
        // Create variables to store identify parameter information  
        //--current map extent (Envelope) 
        var extent = mapView.Extent;
        //--tolerance, in pixels, for finding features  
        var tolerance = 7;
        //--current height, in pixels, of the map control               
        var height = (int)mapView.ActualHeight;
        //--current width, in pixels, of the map control
        var width = (int)mapView.ActualWidth;   
    
        // Create a new IdentifyParameter; pass the variables above to 
        // the constructor
        var identifyParams = new IdentifyParameters(mapPoint, extent, 
        tolerance, height, width);
    
        // Identify only the top most visible layer in the service
        identifyParams.LayerOption = LayerOption.Top;
    
        // Set the spatial reference to match with the map's
        identifyParams.SpatialReference = mapView.SpatialReference;
    
        // Execute the task and await the result
        IdentifyResult idResult = await 
            identifyTask.ExecuteAsync(identifyParams);
    
        // See if a result was returned 
        if (idResult != null && idResult.Results.Count > 0)
        {
            // Get the feature for the first result
            var topLayerFeature = idResult.Results[0].Feature as Graphic;
    
            // do something
        }
    }

Note that this example first takes where the user clicked and converts it to a screen point. Next, that screen location is converted to a MapPoint class. Then, an online service URI is created and passed into the IdentifyTask constructor. Next, the extent, tolerance (in pixels), extent height, and width are created, and then passed into the IdentifyParameters argument, where several parameters are set up. From there, IdentifyTask is executed and IdentifyResult returned so that something can be done with it.

The IdentifyParameters argument has several options, so let's discuss them in more detail. Other than the MapPoint class, you must specify an extent so that it limits the search area to perform the Identify operation. Next is the tolerance. This is the distance in screen pixels from the specified geometry within which to execute the identify operation. The tolerance is very important because it is dependent on the size of the symbol being used for the features. If the symbol is really small, a larger tolerance needs to be used. If the symbol is very large, a smaller tolerance can be used. Lastly, the screen width and height are also specified.

The LayerOption instance allows you to specify that only the Top, Visible, or All layers will be hit tested for the Identify operation. The All option should be used carefully with map services that have many layers, because it can reduce performance. Also, with the Visible option, only layers that have their visibility set to true will be used in the Identify operation. Lastly, if layers are grouped, you must specify the All option; otherwise, nothing will be returned in the layers in GroupLayer.

The LayerIDs property allows you to specify specific layers to perform the Identify operation on. Think of this property as an AND operation. If layer IDs 0 and 1 are specified and are visible, they will be identified.

The offline Identify task using MVVM Light's messenger

Let's add some code, and then discuss how an identify operation works with offline data:

  1. In your project, open the MapViewBehavior.cs file and add the following using statements for Esri.ArcGISRuntime.Tasks.Query and Esri.ArcGISRuntime.Data. Then, add a new event in the OnAttached method, as shown here:
    AssociatedObject.MouseUp += AssociatedObject_MouseUp; 
  2. In the event handler, add the following code:
    MapView mapView = sender as MapView;
    var screenPoint = e.GetPosition(mapView);
    
    // Convert the screen point to a point in map coordinates
    var mapPoint = mapView.ScreenToLocation(screenPoint);
    
    // get the FeatureLayer
    FeatureLayer featureLayer = mapView.Map.Layers[1] as FeatureLayer;
    // Get the FeatureTable from the FeatureLayer.
    Esri.ArcGISRuntime.Data.FeatureTable featureTable = 
        featureLayer.FeatureTable;
    
    // Translate the MapPoint into Microsoft Point object.
    System.Windows.Point windowsPoint = 
        mapView.LocationToScreen(mapPoint);
    // get the Row IDs of the features that are hit
    long[] featureLayerRowIDs = 
        await featureLayer.HitTestAsync(mapView, windowsPoint);
    
    if (featureLayerRowIDs.Length == 1)
    {
    
        // Cause the features in the FeatureLayer to highlight (cyan) in 
        // the Map.
        featureLayer.SelectFeatures(featureLayerRowIDs);
    
        // Perform a Query on the FeatureLayer.FeatureTable using the 
       // ObjectID of the feature tapped/clicked on in the map. 
    
        // Query the layer using the Row IDs
        IEnumerable<GeodatabaseFeature> geoDatabaseFeature = 
            (IEnumerable<GeodatabaseFeature>)await 
        featureTable.QueryAsync(featureLayerRowIDs);
    
        foreach (Esri.ArcGISRuntime.Data.GeodatabaseFeature 
            oneGeoDatabaseFeature in geoDatabaseFeature)
        {
            // Get the desired Field attribute values from the 
            // GeodatabaseFeature.
            System.Collections.Generic.IDictionary<string, object> 
                attributes = oneGeoDatabaseFeature.Attributes;
    
            object postID = attributes["POST_ID"];
    
            // Construct a StringBuilder to hold the text from the Field 
            // attributes.
            System.Text.StringBuilder stringBuilder = new 
                System.Text.StringBuilder();
            stringBuilder.AppendLine("POST ID: " + postID.ToString());
    
            // Send to messenger
            Messenger.Default.Send<NotificationMessage>(new 
            NotificationMessage(stringBuilder.ToString()));
        }
    } 

This code segment essentially produces the same result as the IdentifyTask constructors we used in the previous section, but with one big difference: we didn't use IdentifyTask. The reason for this is that IdentifyTask requires a URI to an online service, but we're using a local ArcGIS Runtime geodatabase. In fact, in the code we're just getting the second layer in the layers that are in the map. Once we get the FeatureTable class of FeatureLayer, we perform a hit test using HitTestAsync on MapView using the Windows point, which is in pixels. This returns a set of row IDs. In this case, we only wanted to perform the hit test on one layer, but we could have easily performed the hit test on whatever layers we wanted (Top, Visible, or All).

Once we have the row IDs, we put them into a selected state. If you zoom in, you'll note that the color of the parking meter has changed to cyan. This means it's selected. This isn't necessary, but it lets the user know what they're identifying. If they missed the right feature, they will immediately know it. Once the feature is selected, we perform a QueryAsync variation using the row IDs. We then iterate over the returned GeodatabaseFeature class and create a dictionary of attributes so that we can retrieve the attribute fields and values. Most importantly, we then sent the attributes in StringBuilder to the MVVM Light messenger we set up in Chapter 2, The MVVM Pattern. As a result of using a custom behavior and the messenger, we've satisfied the notion of SoC.

The Identify options

Some other things to keep in mind include how you want to handle overlays and the Identify operations, as shown in this chapter. For example, if you want to perform an Identify operation and overlay, you'll need to figure out which mouse events to use in Windows. Do you use right-click, left-click, or mouse up? This can get even more complicated in Windows Store because you typically will want to handle MapViewTapped. How will you handle an Identify operation and overlay? You could give the user a dialog that provides an option, or you could pick and choose which layers to use for the overlay and which to use for the Identify operation. Also, when designing an Identify tool, you need to think about which fields to show. If your app has a pre-set list of layers with known fields, this would simply be a matter of hardcoding them in, but that's not the most elegant solution. With Runtime, you can read the layer fields and write your code in such a manner to generate the result dynamically. No matter what, careful consideration should be given to how you implement these interactive tools.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset