ProGuide Templates - Esri/arcgis-pro-sdk GitHub Wiki

Language:      C#
Subject:       Editing
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          10/06/2024
ArcGIS Pro:    3.4
Visual Studio: 2022

Templates are a central concept in the editing environment in ArcGIS Pro. The Editor relies on the use of templates for creating features in feature layers or rows in standalone tables.

This ProGuide demonstrates how to create, modify and use templates. The code used to illustrate this guide can be found at the EditingTemplates Sample.

Prerequisites

Step 1

Add a new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name the item CreateTemplateWithCIM. Modify the Config.daml button item as follows:

  • Change the caption to "Create Template with CIM"
  • Change the tooltip heading to "Create Template With CIM" and the tooltip text to "Creates a new template using the CIM"

Add another new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name this item CreateTemplateWithExt. Modify the config.daml for this button item as follows:

  • Change the caption to "Create Template with Extension"
  • Change the tooltip heading to "Create Template With Extension" and the tooltip text to "Creates a new template using the extension method"

The config.daml should look like the following

<button id="EditingTemplates_CreateTemplateWithCIM" caption="Create Template With CIM" 
              className="CreateTemplateWithCIM" loadOnClick="true" 
              smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
              largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
  <tooltip heading="Create Template With CIM">Creates a new template using the CIM<disabledText /></tooltip>
</button>
<button id="EditingTemplates_CreateTemplateWithExt" caption="Create Template with Extension" 
              className="CreateTemplateWithExt" loadOnClick="true" 
              smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
              largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
  <tooltip heading="Create Template with Extension">Creates a new template using the extension method<disabledText /></tooltip>
</button>

Build the sample. Debug the add-in and start ArcGIS Pro. Open the 'Interacting with Maps' project from the Community Samples Data you previously downloaded. Validate the UI on the ArcGIS Pro ribbon.

templatesRibbon

Close ArcGIS Pro and return to Visual Studio.

Step 2

The Pro API provides access to many of the common objects and methods used within the ArcGIS Pro application. However there are many more objects and properties available via the Cartographic Information Model (CIM); a specification used to persist and transfer cartographic descriptions of GIS datasets such as maps, layers, layouts, symbols and layout elements. The CIM model is represented in XML or JSON and exposed via the ArcGIS.Core.CIM namespace. Here is a list of all the CIM classes. You can use any of these CIM classes to expand upon the managed API.

The pattern for accessing a CIM object is to use the managed_object.GetDefinition method. If you wish to modify a CIM object, use both the managed_object.GetDefinition and managed_object.SetDefinition methods as a pair. These methods need to run on the main CIM thread so are wrapped in a QueenedTask.Run. The following is a typical coding pattern for updating the CIM definition of a managed object:

await QueuedTask.Run(() =>
{
   managed_object.GetDefinition();

   set properties, do other things ....

   managed_object.SetDefinition();
});

In many cases it is often useful to know the json format of a CIM object to ensure you populate the object correctly. You can use the CIM Viewer utility to inspect many CIM models within Pro. You can also access the json yourself by using the CIMObject.ToJson() method in test code within your add-in.

Two of the CIM objects we will use in this guide are the CIMFeatureLayer and CIMRowTemplate objects. Here is a sample of the structure of a CIMRowTemplate object.

{
  "type": "CIMRowTemplate",
  "description": "Template for Point_1",
  "name": "Point_1",
  "tags": "Point",
  "defaultToolGUID": "2a8b3331-5238-4025-972e-452a69535b06",
  "defaultValues": {
    "type": "PropertySet",
    "propertySetItems": [
      "notes",
      "Some note"
    ]
  }
}

This example of a CIMRowTemplate has a name, description, tags, a default tool GUID and a set of default values. We will be creating an object similar to this.

Open the CreateTemplateWithCIM.cs file. Replace the existing empty OnClick method with the following.

  protected override async void OnClick()
  {
    MapView mapvView = MapView.Active;
    if (mapvView == null)
      return;

    // get the Fire Stations layer
    FeatureLayer layer = mapvView.Map.GetLayersAsFlattenedList().
                            OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Fire Stations");
    if (layer == null)
      return;

    await QueuedTask.Run(() =>
    {
      //remove existing templates and regenerate from the renderer
      layer.AutoGenerateTemplates(true);

      //get the CIM layer definition
      var layerDef = layer.GetDefinition() as CIMFeatureLayer;

      //set new template values
      var myTemplateDef = new CIMRowTemplate();
      myTemplateDef.Name = "My template";
      myTemplateDef.Description = "some description";
      myTemplateDef.WriteTags(new[] { "Point", "TesterTag" });

      // set some default attributes
      myTemplateDef.DefaultValues = new Dictionary<string, object>();
      myTemplateDef.DefaultValues.Add("City", "Portland");

      // set the default construction tool
      myTemplateDef.SetDefaultToolID("esri_editing_SketchPointTool");

      // remove construction tools from being available with this template
      List<string> filter = new List<string>();
      // guid = BCCF295A-9C64-4ADC-903E-62D827C10EF7
      filter.Add("esri_editing_ConstructPointsAlongLineCommand");
      myTemplateDef.SetExcludedToolIDs(filter.ToArray());

      //get all templates on this layer
      // NOTE - layerDef.FeatureTemplates could be null 
      //    if Create Features window hasn't been opened
      var layerTemplates = layerDef.FeatureTemplates?.ToList();
      if (layerTemplates == null)
        layerTemplates = new List<CIMEditingTemplate>();

      //add the new template to the layer template list
      layerTemplates.Add(myTemplateDef);

      //update the layerdefinition with the templates
      layerDef.FeatureTemplates = layerTemplates.ToArray();

      // check the AutoGenerateFeatureTemplates flag, 
      //     set to false so our changes will stick
      if (layerDef.AutoGenerateFeatureTemplates)
        layerDef.AutoGenerateFeatureTemplates = false;

      //and commit
      layer.SetDefinition(layerDef);
    });
  }

This subroutine follows the standard CIM pattern of using the GetDefinition method to obtain the CIM layer definition from a feature layer, performs a number of actions to change the CIM defintion (creating a new CIMRowTemplate object and assigning properties), and finishes by calling the SetDefinition method to commit the CIM changes to the feature layer.

The changes to the CIM consist of creating a new CIMRowTemplate object and assigning name, description, tags and default values. The template's default tool is set using the SetDefaultToolID helper method to assign a daml-id. (Note: The json sample of a CIMRowTemplate above shows the defaultToolGUID property which does not use daml-ids; the default construction tool is represented internally using a GUID. This GUID is also a property of a construction tool and can be found defined in the tool's entry in the Editing.daml file. You could use the DefaultToolGUID property on the CIMRowTemplate object to assign the default tool GUID, however we use the SetDefaultToolID helper method to assign the easier to recognize daml-ids.) There is a similar helper method for removing construction tools from being available with the template. You could use the ExcludedToolGUIDs property with an array of tool GUIDs or the SetExcludedToolIDs helper method with an array of tool daml-ids. (If this property was illustrated in our json sample, we would see the ExcludedToolGUIDs property populated with GUID strings.)

Once the template is defined, add it to the template collection from the layer definition. It's necessary to check for a null collection as the template definitions may not exist until the Create Features window has been opened due to loading optimizations. Don't forget to assign the updated template collection back to the layer definition.

Finally, it is also VERY important to check the AutoGenerateFeatureTemplates property on the layer definition. This indicates whether templates are automatically generated by the system. If you are coding modifications to the templates via the CIM, you need to ensure the AutoGenerateFeatureTemplates flag is set to false to ensure your changes are not overwritten by the auto generation logic. If this flag is false, then the layer templates have already been customized and are persisted and auto generation logic is not run.

Build the sample and fix any compile errors. Debug the add-in and start ArcGIS Pro. Open the 'Interacting with Maps' project. Ensure the Fire Stations layer is visible and open the Create Features window (the button is available from the Edit tab). Navigate to the Add-In tab and click the Create Template with CIM button. A new template is created in the Create Features window. Verify the properties of the template by right clicking on the template and choosing Properties and checking the General, Tools and Attributes pages.

CIMTemplate

Close ArcGIS Pro and return to Visual Studio.

Step 3

Open the CreateTemplateWithExt.cs file. We will create a similar template on the same layer using the CreateTemplate extension method. Replace the existing empty OnClick method with the following.

  protected override async void OnClick()
  {
    MapView mapvView = MapView.Active;
    if (mapvView == null)
      return;

    // get the Fire Stations layer
    FeatureLayer layer = mapvView.Map.GetLayersAsFlattenedList().
                            OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Fire Stations");
    if (layer == null)
      return;
   
    await QueuedTask.Run(() =>
    {
      //remove existing templates and regenerate from the renderer
      layer.AutoGenerateTemplates(true);

      // load the schema
      var insp = new Inspector();
      insp.LoadSchema(layer);

      // set some default attributes
      insp["City"] = "Portland";

      // set up tags
      var tags = new[] { "Point", "tag2" };

      // default construction tool - use daml-id
      string defaultTool = "esri_editing_SketchPointTool";

      // filter - use daml-id
      List<string> filter = new List<string>();
      filter.Add("esri_editing_ConstructPointsAlongLineCommand");

      // create a new CIM template  - new extension method
      var newTemplate = layer.CreateTemplate("My extension template", 
                           "sample description", insp, defaultTool, 
                           tags, filter.ToArray());
    });
  }

In this example, use the Inspector object to set default attributes. The default construction tool and tool filters can be specified using daml-ids. Call the CreateTemplate extension method which interacts with the CIM internally and sets the AutoGenerateFeatureTemplates flag appropriately. As you would expect, the extension method hides a lot of the detail required when using the CIM.

Build the sample and fix any compile errors. Debug the add-in and start ArcGIS Pro. Open the 'Interacting with Maps' project. Ensure the Fire Stations layer is visible and open the Create Features window. Navigate to the Add-In tab and click the Create Template with Extension button. A new template is created in the Create Features window. Verify the properties of the template.

ExtensionTemplate

Close ArcGIS Pro and return to Visual Studio.

Step 4

In addition to creating templates, you may wish to modify an existing template. This requires using the CIM pattern shown in Step 2.

Add a new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name the item ModifyTemplateCIM. Modify the Config.daml button item as follows:

  • Change the caption to "Modify Template with CIM"
  • Change the tooltip heading to "Modify Template With CIM" and the tooltip text to "Modify a template using the CIM"
  <button id="EditingTemplates_ModifyTemplateCIM" caption="Modify Template with CIM" 
                 className="ModifyTemplateCIM" loadOnClick="true" 
              smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
              largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
    <tooltip heading="Modify Template with CIM">Modify a template using the CIM<disabledText /></tooltip>
  </button>

Open the ModifyTemplateCIM.cs file and paste the following into the OnClick method.

  protected override async void OnClick()
  {
     MapView mapvView = MapView.Active;
     if (mapvView == null)
       return;

     // get the layer
     FeatureLayer layer = mapvView.Map.GetLayersAsFlattenedList().
                             OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Portland Precincts");
     if (layer == null)
       return;

     await QueuedTask.Run(() =>
     {
       //remove existing templates and regenerate from the renderer
       layer.AutoGenerateTemplates(true);

       // get the template
       var template = layer.GetTemplate("North Precinct");
       if (template != null)
       {
        // get the definition
         var templateDef = template.GetDefinition() as CIMRowTemplate;      
         // change the default tool
         templateDef.SetDefaultToolID("esri_editing_SketchRightPolygonTool");
         // commit the definition
         template.SetDefinition(templateDef);
       }
     });
   }

This button again illustrates the GetDefintion, SetDefinition pattern of accessing the CIM; however this time we access the CIMRowTemplate class from an EditingTemplate object; retrieved using the GetTemplate API method from the FeatureLayer. As before, use the SetDefaultToolID extension method to alter the default construction tool for the template. You can also modify other attributes of the template by using the properties on the CIMRowTemplate object.

Debug and start ArcGIS Pro opening the previous project. Click the Modify Template with CIM button. Activate the North Precinct template in the Create Features pane; notice the new default construction tool is the Right Angle Polygon Tool.

Close ArcGIS Pro and return to Visual Studio.

Step 5

Even though templates are defined with default attribute values, you can use templates at run time and temporarily override these default values. The following example will show you how to activate a template and override it's default attribute values to store three features with different values.

Add a new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name the item CreateFeatures. Modify the Config.daml button item as follows:

  • Change the caption to "Create Features with Template"
  • Change the tooltip heading to "Create Features with Template" and the tooltip text to "Create Features with Template"
  <button id="EditingTemplates_CreateFeatures" caption="Create Features with Template" 
                   className="CreateFeatures" loadOnClick="true" 
              smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
              largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
    <tooltip heading="Create Features with Template">Create Features with Template<disabledText /></tooltip>
  </button>

Open the CreateFeatures.cs file and paste the following into the OnClick method.

    protected override async void OnClick()
    {
      MapView mapvView = MapView.Active;
      if (mapvView == null)
        return;

      // get the Fire Stations layer
      FeatureLayer layer = mapvView.Map.GetLayersAsFlattenedList().
                              OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Fire Stations");
      if (layer == null)
        return;

      await QueuedTask.Run(async () =>
      {
        // use the center of the mapextent as the geometry
        var extent = mapvView.Extent;
        var geometry = extent.Center;
        // set up 2 other geometries offset
        var geometry2 = GeometryEngine.Instance.Move(geometry, extent.Width / 4, extent.Height / 4);
        var geometry3 = GeometryEngine.Instance.Move(geometry, -extent.Width / 4, -extent.Height / 4);

        // get one of the templates
        var template = layer.GetTemplate("Fire Stations");
        if (template != null)
        {
          // activate the template - use the default tool
          await template.ActivateDefaultToolAsync();

          // you can also activate a template via a specific tool 
          // (assuming tool is available for the template)
          // await template.ActivateToolAsync("esri_editing_SketchPointTool");

          // perform the creation
          var op = new EditOperation();
          op.Name = "Create feature";
          // use template default field values
          op.Create(template, geometry);

          // modify default template properties 
          var insp = template.Inspector;
          insp["City"] = "xxx";

          // create with the modified fields and a different geometry
          op.Create(template, geometry2);

          // reset the modified fields back to original defaults
          insp.Cancel();
          // change the field again
          insp["City"] = "yyy";
          // create with the modified fields and a different geometry
          op.Create(template, geometry3);

          // reset the modified fields back to original defaults
          insp.Cancel();

          // execute the operation
          bool result = op.Execute();
        }
      });
    }

Retrieve a template by name from a layer using the GetTemplate method. Activate it by using the ActivateDefaultToolAsync or ActivateToolAsync methods. Then use the template's Inspector to set field values. A template's Inspector object is only available and non-null after the template has been activated. In this example we create 3 features with 3 different City values by overriding the template default attributes, wrapping the feature creation in an EditOperation.

Debug and start ArcGIS Pro, opening the previous project. Click the Create Features with Template button. Three features will be created. Open the Attributes pane and verify the City attribute for each of the new features.

Close ArcGIS Pro and return to Visual Studio.

Step 6

Group templates allow you to create and place many features across multiple layers in one editing action. They are created by choosing an existing feature template as the primary template and adding other templates as component templates to create additional features based on the geometry or location of the primary feature. For example, in the Portland project, you can create a new precinct and configure the component templates to automatically create a fire station and police station at predefined locations relative to that precinct.

Here is the json of the group template we will create in this guide.

{
  "type": "CIMGroupEditingTemplate",
  "description": "some desc",
  "name": "My Group Template",
  "tags": "Group;Polygon",
  "defaultToolGUID": "8f79967b-66a0-4a1c-b884-f44bc7e26921",
  "excludedToolGUIDs": [
    "0a7c16b9-1cfd-467f-8ece-6ba376192431",
    "acd53634-cbc7-44d5-bde9-692fa8d45850",
    "e22f7d98-007d-427c-8282-13704f7c84c3"
  ],
  "baseName": "North Precinct",
  "basePart": {
    "type": "CIMGroupEditingTemplatePart",
    "layerURI": "CIMPATH=portland_crimes/portland_pd_precincts.xml",
    "name": "North Precinct",
    "transformationID": "esri_editing_transformation_polygonPrimaryIdentity"
  },
  "parts": [
    {
      "type": "CIMGroupEditingTemplatePart",
      "layerURI": "CIMPATH=portland_2d/fire_stations.xml",
      "name": "Fire Stations",
      "transformationID": "esri_editing_transformation_pointAtPolygonCentroid"
    },
    {
      "type": "CIMGroupEditingTemplatePart",
      "layerURI": "CIMPATH=portland_2d/police_stations.xml",
      "name": "Police Stations",
      "transformationID": "esri_editing_transformation_pointAtPolygonStart"
    }
  ],
}

The CIMGroupEditingTemplate object is very similar to a CIMRowTemplate in that it has a name, description, tags, default tool and an excluded toolset. It also has properties which define the primary template and the component templates. The primary template is defined using the BaseName and BasePart properties using a CIMGroupEditingTemplatePart object. The component templates are part of the Parts array, each defined using a CIMGroupEditingTemplatePart. In this example, the base template is the 'North Precinct' template followed by 2 parts; a Fire Station template which will create a feature at the centroid of the precinct polygon and a Police Station template which will create a feature at the start point of the precinct polygon.

As you've already seen, a CIM object is typically made up of integers, doubles and strings. This means that items such as tool identifiers, and in this case transformation IDs, are not easily discoverable when looking at the objects documentation. This is why we recommend using the CIM viewer or viewing the json of an existing object to obtain specific information. For this particular object, you can determine all the available transformation ID strings provided by the Editing module by opening the Editing.daml file and searching for the esri_editing_TemplateGroup_BuilderMethods category.

To programmatically create this group template add a new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name the item CreateGroupTemplateWithCIM. Modify the Config.daml button item as follows:

  • Change the caption to "Create Group Template with CIM"
  • Change the tooltip heading to "Create Group Template With CIM" and the tooltip text to "Creates a new Group Template using the CIM"
 <button id="EditingTemplates_CreateGroupTemplateWithCIM" caption="Create Group Template With CIM"
                    className="CreateGroupTemplateWithCIM" loadOnClick="true" 
              smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
              largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
   <tooltip heading="Create Group Template With CIM">
                    Creates a new Group Template using the CIM<disabledText /></tooltip>
 </button>

Open the CreateGroupTemplateWithCIM.cs file and paste the following into the OnClick method.

    protected override async void OnClick()
    {
      MapView mapvView = MapView.Active;
      if (mapvView == null)
        return;

      // get the layers
      FeatureLayer precinctLayer = mapvView.Map.GetLayersAsFlattenedList().
                              OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Portland Precincts");
      FeatureLayer fireLayer = mapvView.Map.GetLayersAsFlattenedList().
                        OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Fire Stations");
      FeatureLayer policeLayer = mapvView.Map.GetLayersAsFlattenedList().
                        OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Police Stations");
      if ((precinctLayer == null) || (fireLayer == null) || (policeLayer == null))
        return;

      await QueuedTask.Run(() =>
      {
        //remove existing templates and regenerate from the renderer
        precinctLayer.AutoGenerateTemplates(true);
        fireLayer.AutoGenerateTemplates(true);
        policeLayer.AutoGenerateTemplates(true);

        // get the templates that will make up the group template
        var precinctTemplate = precinctLayer.GetTemplate("North Precinct");
        var fireTemplate = fireLayer.GetTemplates().FirstOrDefault();
        var policeTemplate = policeLayer.GetTemplates().FirstOrDefault();

        if ((precinctTemplate == null) || (fireTemplate == null) || (policeLayer == null))
          return;

        // group templates are stored on the primary layer
        var layerDef = precinctLayer.GetDefinition() as CIMFeatureLayer;

        //set new template values
        var myGroupTemplateDef = new CIMGroupEditingTemplate();
        myGroupTemplateDef.Name = "My Group Template";
        myGroupTemplateDef.Description = "some desc";
        myGroupTemplateDef.WriteTags(new[] { "Group", "Polygon"});

        // set the default construction tool
        myGroupTemplateDef.SetDefaultToolID("esri_editing_SketchPolygonTool");

        // remove construction tools from being available with this template
        List<string> filter = new List<string>();
        filter.Add("esri_editing_SketchFreehandPolygonTool");
        filter.Add("esri_editing_SketchAutoCompleteFreehandPolygonTool");
        filter.Add("esri_editing_SketchTracePolygonTool");
        myGroupTemplateDef.SetExcludedToolIDs(filter.ToArray());

        // create the base part
        var basepart = new CIMGroupEditingTemplatePart();
        basepart.LayerURI = precinctLayer.URI;
        basepart.Name = precinctTemplate.Name;
        basepart.TransformationID = "esri_editing_transformation_polygonPrimaryIdentity";

        // assign the base part to the groupTemplate
        myGroupTemplateDef.BaseName = basepart.Name;
        myGroupTemplateDef.BasePart = basepart;
        
        // create the component parts
        var part = new CIMGroupEditingTemplatePart();
        part.LayerURI = fireLayer.URI;
        part.Name = fireTemplate.Name;
        part.TransformationID = "esri_editing_transformation_pointAtPolygonCentroid";

        var part2 = new CIMGroupEditingTemplatePart();
        part2.LayerURI = policeLayer.URI;
        part2.Name = policeTemplate.Name;
        part2.TransformationID = "esri_editing_transformation_pointAtPolygonStart";

        // build the list of component templates
        List<CIMGroupEditingTemplatePart> parts = new List<CIMGroupEditingTemplatePart>();
        parts.Add(part);
        parts.Add(part2);
        // assign to the group template
        myGroupTemplateDef.Parts = parts.ToArray();


        //get all templates on this layer
        // NOTE - layerDef.FeatureTemplates could be null 
        //    if Create Features window hasn't been opened
        var layerTemplates = layerDef.FeatureTemplates?.ToList();
        if (layerTemplates == null)
          layerTemplates = new List<CIMEditingTemplate>();

        //add the new template to the layer template list
        layerTemplates.Add(myGroupTemplateDef);

        //update the layerdefinition with the templates
        layerDef.FeatureTemplates = layerTemplates.ToArray();

        // check the AutoGenerateFeatureTemplates flag, 
        //     set to false so our changes will stick
        if (layerDef.AutoGenerateFeatureTemplates)
          layerDef.AutoGenerateFeatureTemplates = false;

        //and commit
        precinctLayer.SetDefinition(layerDef);
      });
    }

Start by retrieving the relevant layers from the active MapView. Then retrieve the necessary templates that the group template is to be based on. Create a new CIMGroupEditingTemplate object and assign the name, description, default construction tool and tool filter. The primary part of the group template is defined using a CIMGroupEditingTemplatePart; specify the layer, template and appropriate transformation ID. The component templates are also defined using a CIMGroupEditingTemplatePart with the appropriate layer, template and transformation ID. Once created, assign these component templates to the group template. Finally add the group template to the FeatureTemplates collection on the layer definition and assign the entire layer definition back to the layer.

Debug and start ArcGIS Pro opening the previous project. Click the Create Group Template with CIM button. A new group template will be added to the Create Features window.

templatesGroupTemplate

Verify the properties of the group template. Activate the template and sketch a polygon. Verify that a fire station and police station feature is created along with the precinct polygon feature. Close ArcGIS Pro and return to Visual Studio.

STEP 7

As we have done previously, we will also create a group template using extension methods. Add a new ArcGIS Pro Add-ins | ArcGIS Pro Button to the project and name the item CreateGroupTemplateWithExt. Modify the Config.daml button item as follows:

  • Change the caption to "Create Group Template with Extension"
  • Change the tooltip heading to "Create Group Template With Extension" and the tooltip text to "Creates a new Group Template using the extension method"
 <button id="EditingTemplates_CreateGroupTemplateWithExt" caption="Create Group Template with Extension" 
                className="CreateGroupTemplateWithExt" loadOnClick="true" 
                smallImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue16.png" 
                largeImage="pack://application:,,,/ArcGIS.Desktop.Resources;component/Images/GenericButtonBlue32.png">
          <tooltip heading="Create Group Template with Extension">
            Creates a new Group Template using the extension method<disabledText /></tooltip>
 </button>

Open the CreateGroupTemplateWithExt.cs file. Replace the existing empty OnClick method with the following code.

    protected override async void OnClick()
    {
      MapView mapvView = MapView.Active;
      if (mapvView == null)
        return;

      // get the layers
      FeatureLayer precinctLayer = mapvView.Map.GetLayersAsFlattenedList().
                              OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Portland Precincts");
      FeatureLayer fireLayer = mapvView.Map.GetLayersAsFlattenedList().
                        OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Fire Stations");
      FeatureLayer policeLayer = mapvView.Map.GetLayersAsFlattenedList().
                        OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "Police Stations");
      if ((precinctLayer == null) || (fireLayer == null) || (policeLayer == null))
        return;

      await QueuedTask.Run(() =>
      {
        // group templates are stored on the primary layer
        var layerDef = precinctLayer.GetDefinition() as CIMFeatureLayer;

        // create group template from primary layer
        var myGroupTemplateDef = precinctLayer.CreateGroupTemplateDefinition("My Group Extension Template", "North Precinct", "some desc", new[] { "Group", "Polygon" });

        // set the default construction tool
        myGroupTemplateDef.SetDefaultToolID("esri_editing_SketchPolygonTool");

        // remove construction tools from being available with this template
        List<string> filter = new List<string>();
        filter.Add("esri_editing_SketchFreehandPolygonTool");
        filter.Add("esri_editing_SketchAutoCompleteFreehandPolygonTool");
        filter.Add("esri_editing_SketchTracePolygonTool");
        myGroupTemplateDef.SetExcludedToolIDs(filter.ToArray());

        // add component parts
        myGroupTemplateDef = myGroupTemplateDef.AddComponentTemplate(fireLayer, "Fire Stations", GroupTemplateBuilderMethods.builderPointAtPolygonCentroid);
        myGroupTemplateDef = myGroupTemplateDef.AddComponentTemplate(policeLayer, "Police Stations", GroupTemplateBuilderMethods.builderPointAtPolygonStart);

        // add group template to layer
        var template = precinctLayer.CreateTemplate(myGroupTemplateDef);
      });
    }

Compile, debug and start ArcGIS Pro opening the previous project. Click the Create Group Template with Ext button. Verify that a new group template is added to the Create Features window with the appropriate properties and tools. Activate the template and sketch a polygon feature. Verify that the component features (police station and fire station) are also created along with the precinct feature.

Close ArcGIS Pro and return to Visual Studio.

⚠️ **GitHub.com Fallback** ⚠️