Getting a featurelayer from a Geoprocessing result

752
7
Jump to solution
04-23-2021 10:59 AM
KenBuja
MVP Honored Contributor

I am creating a featureclass using the following code.

var result = await CreateLayer(System.IO.Path.GetDirectoryName(output), System.IO.Path.GetFileName(output), "POINT", SR.Wkid);
if (result == null) return;

var featurelayer = ?

    public static async Task<IGPResult> CreateLayer(string path, string featureclassName, string featureclassType, int SR_wkid)
    {
      List<object> arguments = new List<object>
      {
        // store the results in the default geodatabase
        //CoreModule.CurrentProject.DefaultGeodatabasePath,
        path,
        // name of the feature class
        featureclassName,
        // type of geometry
        featureclassType,
        // no template
        "",
        // no z values
        "DISABLED",
        // no m values
        "DISABLED"
      };
      await QueuedTask.Run(() =>
      {
        // spatial reference
        arguments.Add(SpatialReferenceBuilder.CreateSpatialReference(SR_wkid));
      });

      IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", Geoprocessing.MakeValueArray(arguments.ToArray()));
      return result;
    }

CreateLayer automatically adds the featureclass to the map. How do I get a reference to this featurelayer? Is this the only way or can I get it directly from the IGResult?

var fcLayer = MapView.Active.Map.GetLayersAsFlattenedList().Where((l) => l.Name == fcName).FirstOrDefault() as BasicFeatureLayer;

 

0 Kudos
1 Solution

Accepted Solutions
Wolf
by Esri Regular Contributor
Esri Regular Contributor

You can disable the automatic adding of the feature class to the current map by changing the GPExecuteToolFlags.AddOutputsToMap option (which is the default) to GPExecuteToolFlags.None, as shown in the snippet below.  

IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", 
        Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);

 After this is done, you can add the layer yourself, as shown in my Button 'OnClick' sample below:

protected override async void OnClick()
{
  await CreateFeatureClass("TTT", EnumFeatureClassType.POINT);
}

public enum EnumFeatureClassType
{
  POINT,
  MULTIPOINT,
  POLYLINE,
  POLYGON
}

/// <summary>
/// Create a feature class in the default geodatabase of the project.
/// </summary>
/// <param name="featureclassName">Name of the feature class to be created.</param>
/// <param name="featureclassType">Type of feature class to be created. Options are:
/// <list type="bullet">
/// <item>POINT</item>
/// <item>MULTIPOINT</item>
/// <item>POLYLINE</item>
/// <item>POLYGON</item></list></param>
/// <returns></returns>
public static async Task CreateFeatureClass(string featureclassName, 
  EnumFeatureClassType featureclassType)
{
  List<object> arguments = new List<object>
  {
    // store the results in the default geodatabase
    CoreModule.CurrentProject.DefaultGeodatabasePath,
    // name of the feature class
    featureclassName,
    // type of geometry
    featureclassType.ToString(),
    // no template
    "",
    // no z values
    "DISABLED",
    // no m values
    "DISABLED"
  };
  await QueuedTask.Run(() =>
  {
    // spatial reference
    arguments.Add(SpatialReferenceBuilder.CreateSpatialReference(3857));
  });
  IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", 
    Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);

  var uri = new Uri(result.ReturnValue);
  var lyr = await QueuedTask.Run<FeatureLayer>(() =>
  {
    var newLayer = LayerFactory.Instance.CreateFeatureLayer(uri,
      MapView.Active.Map, LayerPosition.AddToTop, $@"Lyr-{featureclassName}") as FeatureLayer;
    return newLayer;
  });
  MessageBox.Show($@"Newly added: {lyr.Name}");
}

You can also use the result.ReturnValue GDB  path to find the automatically added layer by comparing all feature layer datasources for the current map.

View solution in original post

0 Kudos
7 Replies
Wolf
by Esri Regular Contributor
Esri Regular Contributor

You can disable the automatic adding of the feature class to the current map by changing the GPExecuteToolFlags.AddOutputsToMap option (which is the default) to GPExecuteToolFlags.None, as shown in the snippet below.  

IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", 
        Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);

 After this is done, you can add the layer yourself, as shown in my Button 'OnClick' sample below:

protected override async void OnClick()
{
  await CreateFeatureClass("TTT", EnumFeatureClassType.POINT);
}

public enum EnumFeatureClassType
{
  POINT,
  MULTIPOINT,
  POLYLINE,
  POLYGON
}

/// <summary>
/// Create a feature class in the default geodatabase of the project.
/// </summary>
/// <param name="featureclassName">Name of the feature class to be created.</param>
/// <param name="featureclassType">Type of feature class to be created. Options are:
/// <list type="bullet">
/// <item>POINT</item>
/// <item>MULTIPOINT</item>
/// <item>POLYLINE</item>
/// <item>POLYGON</item></list></param>
/// <returns></returns>
public static async Task CreateFeatureClass(string featureclassName, 
  EnumFeatureClassType featureclassType)
{
  List<object> arguments = new List<object>
  {
    // store the results in the default geodatabase
    CoreModule.CurrentProject.DefaultGeodatabasePath,
    // name of the feature class
    featureclassName,
    // type of geometry
    featureclassType.ToString(),
    // no template
    "",
    // no z values
    "DISABLED",
    // no m values
    "DISABLED"
  };
  await QueuedTask.Run(() =>
  {
    // spatial reference
    arguments.Add(SpatialReferenceBuilder.CreateSpatialReference(3857));
  });
  IGPResult result = await Geoprocessing.ExecuteToolAsync("CreateFeatureclass_management", 
    Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);

  var uri = new Uri(result.ReturnValue);
  var lyr = await QueuedTask.Run<FeatureLayer>(() =>
  {
    var newLayer = LayerFactory.Instance.CreateFeatureLayer(uri,
      MapView.Active.Map, LayerPosition.AddToTop, $@"Lyr-{featureclassName}") as FeatureLayer;
    return newLayer;
  });
  MessageBox.Show($@"Newly added: {lyr.Name}");
}

You can also use the result.ReturnValue GDB  path to find the automatically added layer by comparing all feature layer datasources for the current map.

0 Kudos
KenBuja
MVP Honored Contributor

Thanks, the GPExecuteToolFlags.None option is good to know. I had figured out to use the LayerFactory, but didn't know how to get around the automatic add.

0 Kudos
JCLaurence
New Contributor

Hi Wolf,

I am new to this forum and am not sure if this qualifies as a new question.  I have a scenario similar to your answer code above.  However, the geoprocessing tool I am running is one that generates a layer rather than writing a feature class to disk.  This tool could be "MakeFeatureLayer_management" or "AddJoin_management", for example.  I DO NOT want this geoprocessing tool output to be added as a layer to the map.  My issue is this: those geoprocessing tools run properly and output the layer name as a string value which I can retrieve.  However, I am unsure how to pass a reference to the freshly-created layer to the next tool (e.g. "CopyFeatures_management") in my code.  If I allow tool output to be added to my map, I can find that layer based on the tool output name, but if I do not allow the output to be added to the map, then my next tools (e.g. "CopyFeatures_management") do not recognize the output name as a valid input.  It is as if the "MakeFeatureLayer_management" tool's layer output simply vanishes and is unreferenceable by subsequent tools, UNLESS the layer is added by the tool to the map.

See your code fragment below - I've replaced "CreateFeatureclass_management" with "MakeFeatureLayer_management".  GPExecuteToolFlags.None will ensure that no layer gets output to the map.  So, how can I pass on the new feature layer output by this tool to my next tool as an input (e.g. CopyFeatures_management)??

IGPResult result = await Geoprocessing.ExecuteToolAsync("MakeFeatureLayer_management",
Geoprocessing.MakeValueArray(arguments.ToArray()), null, null, null, GPExecuteToolFlags.None);

Hopefully I am just missing a simple solution to this scenario.  Python allows the user to use the output of a layer-producing tool (a name string) as an input to the next tool even if the tool outputs are not loaded into the map.  I don't see how to do this using the .NET SDK.  help!

 

 

0 Kudos
happygis
New Contributor II

I have the same scenario , The AddJoin GP tool, I don't want to add the output layer to the map.Has the problem been solved?

 

0 Kudos
KenBuja
MVP Honored Contributor

Did you see the answer accepted as the solution?

You can disable the automatic adding of the feature class to the current map by changing the GPExecuteToolFlags.AddOutputsToMap option (which is the default) to GPExecuteToolFlags.None, as shown in the snippet below.

0 Kudos
DHuantes
New Contributor III

Our team, like you, initially had a method called CreateFeatureLayer but your method like ours was actually calling a GP Tool (CreateFeatureclass_management) that is creating a FeatureClass.   And it just so happens that the default behavior of the Geoprocessing.ExecuteToolAsync() method is to also add the FeatureClass to the active map as a FeatureLayer.  But there are times you don't want to do this and the accepted solution is the way to go.  I would recommend you change the name of your method to CreateFeatureClass.  That's what we did and we also added a boolean option to Add to Map that defaults to false so you have the option to do so or not.

Additionally, there are times you do need to find if a layer has been added or not and obtain a reference to the same.  I prefer the code snippet below unless there is a better one.

FeatureLayer l_returnLayer = MapView.Active.Map.FindLayers(a_layerName).FirstOrDefault() as FeatureLayer;

 

0 Kudos
RichRuh
Esri Regular Contributor

Pro 2.8 will contain some DDL functionality, in case you want to create a table without adding it to the map.

--Rich

0 Kudos