Get existing graphics on featurelayer?

1981
12
05-11-2018 10:38 AM
ShawnCastrianni
New Contributor II

In the old versions, a FeatureLayer extended GraphicsLayer such that I could directly access the graphics on a loaded feature layer from URL.  That no longer seems to be the case.  If I wanted to loop through all the graphics on a feature layer, how would I do that?  I don't want to call QueryFeatures as I think that goes back to the server.  They have already been loaded from the server and are visible on the map.

0 Kudos
12 Replies
dotMorten_esri
Esri Notable Contributor

> I don't want to call QueryFeatures as I think that goes back to the server.

That's how it's done though. What's in local memory will only have a subset of attributes used for rendering, only what's in view and might be heavily generalized etc to improve rendering performance significantly.

0 Kudos
ShawnCastrianni
New Contributor II

Maybe if I try to explain what I am trying to do.  I want to programmatically select a feature and open its callout based on attribute values of that feature, not an x,y.  I tried running a query to get the feature (which I didn't want to do because if it goes to the server and back, it is a waste of time since the feature is already loaded and on the map) and then select that feature.  Nothing happened on the select.  My guess is because the feature I get back from the query is a different instance from the feature that was loaded on the map.  So I was looking for a way to find the feature that is already loaded on the map.

One way to do that is IdentifyFeature, but that requires an x,y as if the user touched it.  I need QueryParameters to locate my feature using attributes already loaded on the map.  In the old days, I just manually looped through the Graphics collection available on all layers (including feature layers).

0 Kudos
dotMorten_esri
Esri Notable Contributor

The implementation of FeatureLayers in 100.x is significantly different and optimized to handle 100s of thousands of features while maintaining a low memory footprint. There are no longer any "instances" of graphics in memory when it comes to features in feature layers. The reason the instance is different is because it's more akin of reading a row out of a database each time, so a new managed instance representing that row will be made, and we don't keep those instances floating around in memory.

If you want to ensure no webrequests are made, you need to use the manual cache mode where you manually load data from the server with the populate method, and from then on queries are performed locally. Just note this could significantly reduce startup performance of your layer, and would be closer to the performance you had "in the old days" ..

I'm curious why you can't use the identify operation? (You can use the LocationToScreen to convert a map coordinate to the screen location)

0 Kudos
ShawnCastrianni
New Contributor II

Thanks.  I may look into manual caching.

It sounds like my guess of the two managed instances being different causing the select to not work was correct?  If the new feature layer design is to keep a low memory footprint, then I think it would be very important for the feature instances to not matter.  If I say select a feature with a different instance, it should use the OBJECTID of my instance and select the feature instance that IS loaded in the map with that same OBJECTID.  But I am just getting used to the new 100.X design so this may not make sense.

I don't use the identify operation because I don't have any coordinates.  In addition to our map services, we also have data services from a different data source.  I have a non-map page that lists wells.  This list contains a UWI (Unique Well Identifier) property.  When the user clicks a row in this list, I want the corresponding well feature to be selected and called out in the map view.  So the only information I have is the UWI which is also one of the attributes on the feature graphic.  So I need to programmatically select a feature graphic on the map that is already loaded and visible with a query definition of "'UWI = 'ABCDEF"".

Based on the information you are providing, it sounds like, I have 2 choices:

  1. Use manual caching where I control the ServiceFeatureTable and when items are loaded into cache using PopulateFromService.  I assume then that I can loop through the features in the ServiceFeatureTable since I am in manual cache mode and look for a feature with a specific UWI and then select it?  Or maybe I have to use FeatureCollectionTable?  Not sure, I haven't looked into manual caching yet.
  2. Keep everything the way it is, but when I want to select a feature based on UWI, I must first make a server query with that UWI to get back the lat,lon of that feature, then do an Identify using that lat,lon, then loop through all the features that came back from the identify since more than 1 can be in the same spot on the map and select the one with the correct UWI and open its callout?
0 Kudos
dotMorten_esri
Esri Notable Contributor

Regarding (2), you'd just query that specific feature, and then select it directly on the feature layer with "featureLayer.SelectFeature(feature)". No reason to convert to a point, then identify call select (internally the object id of that feature will be used to select it on the map, not the instance itself).

Since you're just querying a single feature (assuming that's the only one matching your UWI query), the server-query should be very quick.

If I say select a feature with a different instance, it should use the OBJECTID of my instance and select the feature instance that IS loaded in the map

There is no instance anywhere on the map. Everything is running in native code with lots of smarts for streaming the features into the mapview. This is part of the reason we can now handle a MUCH MUCH larger amount of features in the featurelayer compared to the older technology.

0 Kudos
ShawnCastrianni
New Contributor II

That is what I said near the beginning of this thread:  "I tried running a query to get the feature and then select that feature.  Nothing happened on the select."  Let me try again as maybe I am remembering wrong.

0 Kudos
ShawnCastrianni
New Contributor II

I tried again, and I remembered CORRECTLY.  If I use Identify on a featurelayer and select that identified feature, selection works.  If I use Query on a featurelayer's servicefeaturetable, I can get back the correct feature, but when I try to select that feature, nothing happens.

        public async override Task<bool> ShowWellInLayer(string uwi,string layerName,DataTypes dataType)
        {
            FeatureLayer featureLayer = GetMapLayerWithName(layerName) as FeatureLayer;
            if (featureLayer == null)
                return(false);
            QueryParameters parms = new QueryParameters {
                WhereClause = dataType.UWIESRIFieldName() + " = '" + uwi + "'"
            };
            FeatureQueryResult result = await ((ServiceFeatureTable)featureLayer.FeatureTable).QueryFeaturesAsync(parms, QueryFeatureFields.LoadAll);
            Feature feature = result.FirstOrDefault();
            if(feature != null) {
                //if (_mapCallback != null)
                    //_mapCallback.MapCallout(feature);
                //if (_calloutCallback != null) {
                    featureLayer.SelectFeature(feature);
                    //_calloutCallback.ShowMapCalloutView();
                //}
                return (true);
            }
            return(false);
        }

0 Kudos
dotMorten_esri
Esri Notable Contributor

I'm not able to reproduce this issue. Selection works with both query and identify. Is there any chance you can build a small app that reproduces it with a public service?

0 Kudos
ShawnCastrianni
New Contributor II

What is an example public feature service I can use in the test program?

0 Kudos