ProGuide Construction Tools with Options - kataya/arcgis-pro-sdk GitHub Wiki

Language:      C#
Subject:       Editing
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          11/24/2020
ArcGIS Pro:    2.7
Visual Studio: 2017, 2019

This ProGuide demonstrates how to create a construction tool with options allowing users to provide values at run-time. This feature functionality is new at ArcGIS Pro 2.0. The interface IEditingCreateToolControl has been added to allow this feature. Use this in conjunction with a new daml category esri_editing_tool_options to gain the ability to configure construction tools with options which can be saved as part of the project.

The code used to illustrate this add-in can be found at Construction Tool with Options Sample.

Prerequisites

  • Download and install the sample data required for this guide as instructed in Arcgis Pro SDK Community Samples Releases.
  • Create a new ArcGIS Pro Module Add-in, and name the project ConstructionToolWithOptions. If you are not familiar with the ArcGIS Pro SDK, you can follow the steps in the ProGuide Build your first add-in to get started.
  • Add a new ArcGIS Pro Add-ins | ArcGIS Pro Construction Tool item to the add-in project, and name the item BufferedLineTool.
  • Add a new ArcGIS Pro Add-ins | ArcGIS Pro Embeddable Control item to the add-in project, and name the item BufferedLineToolOptions.

Step 1

Change the construction tool to create polygon features by buffering a sketch line geometry. You will achieve this by performing the following.

Modify the config.daml file tool item

  • Change the caption to "Buffered Line".
  • Change the categoryRefID to "esri_editing_construction_polygon" indicating you will create polygon features.
  • Change the tooltip heading to "Buffered Line" and the ToolTip text to "Create a polygon with a fixed buffer.".
<controls>
  <!-- add your controls here -->
  <tool id="ConstructionToolWithOptions_BufferedLineTool" 
        categoryRefID="esri_editing_construction_polygon"
        caption="Buffered Line" className="BufferedLineTool" 
        loadOnClick="true" 
        smallImage="Images\GenericButtonRed16.png" largeImage="Images\GenericButtonRed32.png">
    <tooltip heading="Buffered Line">Create a polygon with a fixed buffer.<disabledText /></tooltip>
  </tool>
</controls>

Modify the BufferedLineTool.cs file as follows

  • Change the SketchType in the constructor to be SketchGeometryType.Line. This is the geometry of the map tool feedback used to symbolize the user interaction (i.e. the user will sketching a line).
   public BufferedLineTool()
   {
     IsSketchTool = true;
     UseSnapping = true;
     // Select the type of construction tool you wish to implement.  
     // Make sure that the tool is correctly registered with the 
     // correct component category type in the daml 
     SketchType = SketchGeometryType.Line;
   }
  • Modify OnSketchCompleteAsync so that the line sketch geometry is buffered to a polygon by calling GeometryEngine.Instance.Buffer with a preset distance value. The ability to allow user defined buffer distances as part of the tool will be covered in steps later in this guide. Pass this buffered geometry to the create operation.
   private double BufferDistance = 25.0;

   /// <summary>
   /// Called when the sketch finishes. This is where we will create the sketch operation and then execute it.
   /// </summary>
   /// <param name="geometry">The geometry created by the sketch.</param>
   /// <returns>A Task returning a Boolean indicating if the sketch complete event was successfully handled.</returns>
   protected override Task<bool> OnSketchCompleteAsync(Geometry geometry)
   {
     if (CurrentTemplate == null || geometry == null)
       return Task.FromResult(false);

     // create the buffered geometry
     Geometry bufferedGeometry = GeometryEngine.Instance.Buffer(geometry, BufferDistance);

     // Create an edit operation
     var createOperation = new EditOperation();
     createOperation.Name = string.Format("Create {0}", CurrentTemplate.Layer.Name);
     createOperation.SelectNewFeatures = true;

     // Queue feature creation
     createOperation.Create(CurrentTemplate, bufferedGeometry);

     // Execute the operation
     return createOperation.ExecuteAsync();
   }

Build your add-in. Debug the add-in. Open the C:\Data\FeatureTest\FeatureTest.aprx project. Verify that your construction tool appears on the polygon layer. Activate the tool and create a new polygon feature by sketching a line.

ProGuide: Editing - Custom Construction tool

Step 2

Add the ability to configure the tools buffer distance by using the embeddable control you previously added. Allowing run-time customizations to construction tools is new at ArcGIS Pro 2.0. A new daml category has been added esri_editing_tool_options in addition to a new interface which needs to be implemented.

The first step is to register the embeddable control as being part of the new tool options category.

Modify the config.daml file

  • Change the embeddable control BufferedLineToolOptions definition by registering the component with the esri_editing_tool_options category rather than the esri_embeddableControls category.
<updateCategory refID="esri_editing_tool_options">
  <insertComponent id="ConstructionToolWithOptions_BufferedLineToolOptions" className="BufferedLineToolOptionsViewModel">
    <content className="BufferedLineToolOptionsView" />
  </insertComponent>
</updateCategory>

Secondly we need to change the BufferedLineToolOptions view to obtain a buffer distance from the user.

  • Modify the BufferedLineToolOptions.xaml file and replace the TextBlock tag so the Grid definition looks like below
<Grid Margin="30,0">
 <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
   <Label Content="Buffer distance:" Foreground="{StaticResource Esri_Gray155}" />
   <TextBox Text="{Binding Path=Buffer, UpdateSourceTrigger=PropertyChanged}" Margin="6,0,0,0" Width="75"/>
 </StackPanel>
</Grid>

Finally we need to modify the BufferedLineToolOptions view model to implement the IEditingCreateToolControl interface, to add a Buffer property and the ability to read and write the buffer distance to the tool options.

Modify the BufferedLineToolOptionsViewModel.cs file and add the IEditingCreateToolControl to the class definition along with a default implementation.

internal class BufferedLineToolOptionsViewModel : EmbeddableControl, IEditingCreateToolControl
{
  ....

   #region IEditingCreateToolControl

   /// <summary>
   /// Gets the optional icon that will appear in the active template pane as a button selector.  
   /// If returning null then the Tool's small image that is defined in DAML will be used. 
   /// </summary>
   ImageSource IEditingCreateToolControl.ActiveTemplateSelectorIcon => null;

   private bool _isValid;
   /// <summary>
   /// Set this flag to indicate if too options are valid and ready for saving.
   /// </summary>
   /// <remarks>
   /// When this IEditingCreateToolControl is being displayed in the Template Properties
   /// dialog, calling code will use this property to determine if the current Template
   /// Properties may be saved.
   /// </remarks>
   bool IEditingCreateToolControl.IsValid => _isValid;

   private bool _isDirty;
   /// <summary>
   /// Set this flag when any tool options have been changed.
   /// </summary>
   /// <remaarks>
   /// When this IEditingCreateToolControl is being displayed in the Template Properties
   /// dialog, the calling code will use this property to determine if any changes have
   /// been made.  
   /// </remaarks>
   bool IEditingCreateToolControl.IsDirty => _isDirty;

   /// <summary>
   /// Gets if the contents of this control is auto-Opened in the Active Template Pane when the 
   /// tool is activated.
   /// </summary>
   /// <param name="toolID">the ID of the current tool</param>
   /// <returns>True the active template pane will be opened to the tool's options view.
   /// False, nothing in the active template pane changes when the tool is selected.</returns>
   bool IEditingCreateToolControl.AutoOpenActiveTemplatePane(string toolID)
   {
     return true;
   }

   /// <summary>
   /// Called just before ArcGIS.Desktop.Framework.Controls.EmbeddableControl.OpenAsync
   /// when this IEditingCreateToolControl is being used within the ActiveTemplate pane.
   /// </summary>
   /// <param name="options">tool options obtained from the template for the given toolID</param>
   /// <returns>true if the control is to be displayed in the ActiveTemplate pane.. False otherwise</returns>
   bool IEditingCreateToolControl.InitializeForActiveTemplate(ToolOptions options)
   {
     return true;
   }

   /// <summary>
   /// Called just before ArcGIS.Desktop.Framework.Controls.EmbeddableControl.OpenAsync
   /// when this IEditingCreateToolControl is being used within the Template Properties
   /// dialog
   /// </summary>
   /// <param name="options">tool options obtained from the template for the given toolID</param>
   /// <returns>true if the control is to be displayed in Template Properties. False otherwise</returns>
   bool IEditingCreateToolControl.InitializeForTemplateProperties(ToolOptions options)
   {
     return false;     // don't show the options in template properties
   }

   #endregion
}

Additional functionality is required for the InitializeForActiveTemplate method. This method is called before the embeddable control is opened within the ActiveTemplate pane allowing you to configure your options view from the values stored with the tool. We will modify the function to the following

   bool IEditingCreateToolControl.InitializeForActiveTemplate(ToolOptions options)
   {
     // assign the current options
     ToolOptions = options;
     // initialize the view
     InitializeOptions();
     return true;    // true <==> do show me in ActiveTemplate;   false <==> don't show me
   }

Take the options passed as the function parameter and assign to an internal variable. Then call the InitializeOptions method to initialize the view. ToolOptions and the InitializeOptions method are defined as follows

   internal const string BufferOptionName = "Buffer";
   internal const double DefaultBuffer = 25.0;

   private ToolOptions ToolOptions { get; set; }
   private void InitializeOptions()
   {
     // no options
     if (ToolOptions == null)
       return;

     // if buffer exists in options, retrieve it
     if (ToolOptions.ContainsKey(BufferOptionName))
       _buffer = (double)ToolOptions[BufferOptionName];
     else
     {
       // otherwise assign the default value and add to the ToolOptions dictionary
       _buffer = DefaultBuffer;
       ToolOptions.Add(BufferOptionName, _buffer);
       // ensure options are notified that changes have been made
       NotifyPropertyChanged(BufferOptionName);
     }
   }

Finally add a Buffer property to bind to in the xaml. Make sure that the ToolOptions are modified with the value within the setter.

   // binds in xaml
   private double _buffer;
   public double Buffer
   {
     get { return _buffer; }
     set
     {
       if (SetProperty(ref _buffer, value))
       {
         _isDirty = true;
         _isValid = true;
         // add/update the buffer value to the tool options
         if (!ToolOptions.ContainsKey(BufferOptionName))
           ToolOptions.Add(BufferOptionName, value);
         else
           ToolOptions[BufferOptionName] = value;
         // ensure options are notified
         NotifyPropertyChanged(BufferOptionName);
       }
     }
   }

Step 3

Now that the options view and view model are defined the final step is to link the options to the construction tool. This can be accomplished by the following

Modify the config.daml file

  • Change the tool definition to include a reference to the options by including a content tag with the toolOptionsID attribute.
<tool id="ConstructionToolWithOptions_BufferedLineTool" categoryRefID="esri_editing_construction_point" 
            caption="Buffered Line" className="BufferedLineTool" 
            loadOnClick="true" 
            smallImage="Images\GenericButtonRed16.png" largeImage="Images\GenericButtonRed32.png">
  <tooltip heading="Buffered Line">Create a polygon with a fixed buffer.<disabledText /></tooltip>
  <content toolOptionsID="ConstructionToolWithOptions_BufferedLineToolOptions" />
</tool>

Finally revisit the construction tool (BufferedLineTool.cs) and replace the BufferDistance property with the following

    private ReadOnlyToolOptions ToolOptions => CurrentTemplate?.GetToolOptions(ID);

    private double BufferDistance
    {
      get
      {
        if (ToolOptions == null)
          return BufferedLineToolOptionsViewModel.DefaultBuffer;

        return ToolOptions.GetProperty(BufferedLineToolOptionsViewModel.BufferOptionName, BufferedLineToolOptionsViewModel.DefaultBuffer);
      }
    }

Rebuild the add-in. Fix any compilation errors. Run the debugger and start ArcGIS Pro. Open the C:\Data\FeatureTest\FeatureTest.aprx project. Choose the construction tool and see the options page appear. Enter a buffer distance and sketch a line. See the buffered feature created. Enter a different distance and sketch another line.

ProGuide: Editing - Custom Construction tool with Option

Additional examples of this pattern have been included in the sample Construction Tool with Options.

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