Need to get selected features for Geoprocessing.ExecuteToolAsync

1268
7
05-11-2019 01:45 PM
MattWashburn1
New Contributor II

I'm trying to execute the CalculateGeometryAttributes geoprocessing tool with some hard-coded arguments. The code I have is working, but it's running on the entire feature class. I need it to only run on the selected records. Here is what I have now:

//// Tool parameters
string in_features = @"C:PathToFeatureClass";
string geometry_property = "SEG_LEN LENGTH";
string length_unit = "MILES_US";

//// Path to tool using toolbox alias
string tool_path = "management.CalculateGeometryAttributes";

//// Construct the value array to be passed as parameter to ExecuteToolAsync
var args = await QueuedTask.Run(() =>
{
    // Create spatial reference and pass to value array constuctor 
    var spatial_ref = SpatialReferenceBuilder.CreateSpatialReference(3081);
    return Geoprocessing.MakeValueArray(in_features, geometry_property, length_unit, null, spatial_ref);
});

//// Execute the tool with hard-coded args
await Geoprocessing.ExecuteToolAsync(tool_path, args); ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I'm assuming I need to somehow check if any features are selected, then pass just those selected to the tool. Otherwise, it should run on all features.

Any help is appreciated! 

0 Kudos
7 Replies
BrianBulla
Regular Contributor

There's different ways to do this.  If this is for a specific layer, you could try something like this...

Get the selected features:

                //****Get all of the selected ObjectIDs from the VLS layer.
                var vlsLayer = MapView.Active.Map.FindLayers("GISWRKS1.WORKS.VLS_Points").First() as BasicFeatureLayer;
                var selection = vlsLayer.GetSelection();
                IReadOnlyList<long> selectedOIDs = selection.GetObjectIDs();  //save the selected OBJECTIDs to a list.

Then process them:

                    foreach (var oid in selectedOIDs)
                    {
                        //do something
                    }
‍‍

To check for the number of selected features:

vlsLayer.SelectionCount
MattWashburn1
New Contributor II

Thanks Brian! This worked to get the selection, then write it to a list and cast to an array.

I'm using the selected OIDs to set a Definition Query and then running the GP tool on the queried out layer. After it's done, I reset the original DefQuery if one existed:

protected async override void OnClick()
  {
    //// TOOL PARAMETERS
    var in_features = MapView.Active.Map.FindLayers("Roadways_Edits").First() as BasicFeatureLayer;
    var currentDefQuery = in_features.DefinitionQuery;
    // Get selected OIDs and set Def Query based on selection 
    await QueuedTask.Run(() =>
      {
        var getSelected = in_features.GetSelection();
        var selectionList = in_features.GetSelection().GetObjectIDs().ToList();
        string combinedString = string.Join(",", selectionList.ToArray());
        in_features.SetDefinitionQuery(String.Format("OBJECTID IN ({0})", combinedString));
      });
    string geometry_property = "SEG_LEN LENGTH"; //this is ["SEG_LEN", "LENGTH"]
    string length_unit = "MILES_US";

    //// PATH TO TOOL USING TOOLBOX ALIAS
    string tool_path = "management.CalculateGeometryAttributes";

    //// CONSTRUCT THE VALUE ARRAY 
    var args = await QueuedTask.Run(() =>
      {
        // Create spatial reference and pass to value array constuctor 
        var spatial_ref = SpatialReferenceBuilder.CreateSpatialReference(3081);
        return Geoprocessing.MakeValueArray(in_features, geometry_property, length_unit, null, spatial_ref);
      });

    //// RUN GP TOOL ASYNC
    await Geoprocessing.ExecuteToolAsync(tool_path, args);

    //// RESET DEF QUERY
    await QueuedTask.Run(() =>
      {
        in_features.SetDefinitionQuery(currentDefQuery);
      });
  }
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This method works, but seems a bit clunky. One issue I'm seeing is that the DefQuery persists in the FeatureLayer options menu.

Is there another way to run this tool on the selected OIDs without a setting a Definition Query? 

0 Kudos
BrianBulla
Regular Contributor

Hi Matt,

Maybe I don't totally know what your doing, but if you start off with the features already being selected I wouldn't think you would need to set the definition query of the layer to.  Can't you just run the GP Tool on the selected features?? 

Perhaps using in_features.GetSelection() might get you where you want to go.

I haven't done any coding use GP tools, so I could be totally wrong.

MattWashburn1
New Contributor II

Hi Brian,

I tried that, but no luck. The GP tool takes a Feature Layer object as the first parameter. The GetSelection() method returns a Selection-typed object which causes the GP tool to throw an exception.

Maybe there's a way to make a new Feature Layer in memory from the selection and run the tool on that. Problem there is that I would then need to somehow update the original feature class with the new values.

However...I'm new to C# and the arcgis pro sdk, to it's very likely that I'm missing something simple.

0 Kudos
BrianBulla
Regular Contributor

Hi Matt,

I've been messing with this and this seems to work for me.  Using the "Calculate GeometryAttributes_management" tool, I call the tool while I have features selected, and it updates the fields as specified in my 'args'.  It seems like as long you have features selected, the GP Tool only processes the selected ones.

See below:

namespace GP_Test
{
    internal class Button1 : Button
    {
        protected override void OnClick()
        {
            QueuedTask.Run(() =>
            {
                //****Get the the VLS layer.
                var vlsLayer = MapView.Active.Map.FindLayers("GISWRKS1.WORKS.VLS_Points_FGDB").First() as BasicFeatureLayer;

                //this is not necessary
                var selection = vlsLayer.GetSelection();                                
                ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show(selection.GetCount().ToString());

                //run the GP tool
                var args = Geoprocessing.MakeValueArray(vlsLayer, "COMMENTS POINT_X");                
                Geoprocessing.ExecuteToolAsync("CalculateGeometryAttributes_management", args);                
            });


        }
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

MattWashburn1
New Contributor II

Ok, so why do things the easy way? This works, thank you! 

I think I know what the problem was. Because this has to be run on the MCT, I was setting the OnClick() event to async and using "await" on Geoprocessing.ExecuteToolAsync(). That wasn't necessary, and prevented the tool from operating on the selection.

Thanks again!

0 Kudos
BrianBulla
Regular Contributor

Good to know....glad you got it working!

0 Kudos