View in MAUI WPF WinUI View on GitHub

Use the Programmatic Reticle Tool to edit and create geometries with programmatic operations to facilitate customized workflows such as those using buttons rather than tap interactions.

EditGeometriesWithProgrammaticReticleTool

Use case

A field worker can use a button driven workflow to mark important features on a map. They can digitize features like sample or observation locations, fences, pipelines, and building footprints using point, multipoint, polyline, and polygon geometries. To create and edit geometries, workers can use a vertex-based reticle tool to specify vertex locations by panning the map to position the reticle over a feature of interest. Using a button driven workflow they can then place new vertices or pick up, move and drop existing vertices.

How to use the sample

To create a new geometry, select the geometry type you want to create (i.e. points, multipoints, polyline, or polygon) in the settings view. Press the button to start the geometry editor, pan the map to position the reticle then press the button to place a vertex. To edit an existing geometry, tap the geometry to be edited in the map and perform edits by positioning the reticle over a vertex and pressing the button to pick it up. The vertex can be moved by panning the map and dropped in a new position by pressing the button again.

Vertices can be selected and the viewpoint can be updated to their position by tapping them.

Vertex creation can be disabled using the switch in the settings view. When this switch is toggled off new vertex creation is prevented, existing vertices can be picked up and moved, but mid-vertices cannot be selected or picked up and will not grow when hovered. The feedback vertex and feedback lines under the reticle will also no longer be visible.

Use the buttons in the settings view to undo or redo changes made to the geometry and the cancel and done buttons to discard and save changes, respectively.

How it works

  1. Create a GeometryEditor and set it to the MapView using MyMapView.GeometryEditor.
  2. Start the GeometryEditor using GeometryEditor.Start(GeometryType) to create a new geometry or GeometryEditor.Start(Geometry) to edit an existing geometry.
    • If using the Geometry Editor to edit an existing geometry, the geometry must be retrieved from the graphics overlay being used to visualize the geometry prior to calling the start method. To do this:
      • Use MapView.IdentifyGraphicsOverlayAsync(...) to identify graphics at the location of a tap.
      • Access the MapView.IdentifyGraphicsOverlayAsync(...).
      • Find the desired graphic in the results.FirstOrDefault() list.
      • Access the geometry associated with the Graphic using Graphic.Geometry - this will be used in the GeometryEditor.Start(Geometry) method.
  3. Create a ProgrammaticReticleTool and set the GeometryEditor.Tool.
  4. Add event handlers to listen to GeometryEditor.HoveredElementChanged and GeometryEditorPickedUpElementChanged.
    • These events can be used to determine the effect a button press will have and set the button text accordingly.
  5. Listen to tap events when the geometry editor is active to select and navigate to tapped vertices and mid-vertices.
    • To retrieve the tapped element and update the viewpoint:
      • Use MapView.IdentifyGeometryEditorAsync(...) to identify geometry editor elements at the location of the tap.
      • Access the MapView.IdentifyGeometryEditorAsync(...).
      • Find the desired element in the results.Elements.FirstOrDefault() list.
      • Depending on whether or not the element is a GeometryEditorVertex or GeometryEditorMidVertex use GeometryEditor.SelectVertex(...) or GeometryEditor.SelectMidVertex(...) to select it.
      • Update the viewpoint using MapView.SetViewpointAsync(...).
  6. Enable and disable the vertex creation preview using ProgrammaticReticleTool.VertexCreationPreviewEnabled.
    • To prevent mid-vertex growth when hovered use ProgrammaticReticleTool.Style.GrowEffect.ApplyToMidVertices.
  7. Check to see if undo and redo are possible during an editing session using GeometryEditor.CanUndo and GeometryEditor.CanRedo. If it’s possible, use GeometryEditor.Undo() and GeometryEditor.Redo().
    • A picked up element can be returned to its previous position using GeometryEditor.CancelCurrentAction(). This can be useful to undo a pick up without undoing any change to the geometry. Use the GeometryEditor.PickedUpElement property to check for a picked up element.
  8. Check whether the currently selected GeometryEditorElement can be deleted (GeometryEditor.SelectedElement.CanDelete). If the element can be deleted, delete using GeometryEditor.DeleteSelectedElement().
  9. Call GeometryEditor.Stop() to finish the editing session and store the Graphic. The GeometryEditor does not automatically handle the visualization of a geometry output from an editing session. This must be done manually by propagating the geometry returned into a Graphic added to a GraphicsOverlay.
    • To create a new Graphic in the GraphicsOverlay:
      • Using Graphic(Geometry), create a new Graphic with the geometry returned by the GeometryEditor.Stop() method.
      • Append the Graphic to the GraphicsOverlay(i.e. GraphicsOverlay.Graphics.Add(Graphic)).
    • To update the geometry underlying an existing Graphic in the GraphicsOverlay:
      • Replace the existing Graphic’s Geometry property with the geometry returned by the GeometryEditor.Stop() method.

Relevant API

  • Geometry
  • GeometryEditor
  • Graphic
  • GraphicsOverlay
  • MapView
  • ProgrammaticReticleTool

Additional information

The sample demonstrates a number of workflows which can be altered depending on desired app functionality:

  • picking up a hovered element combines selection and pick up, this can be separated into two steps to require selection before pick up.

  • tapping a vertex or mid-vertex selects it and updates the viewpoint to its position. This could be changed to not update the viewpoint or also pick up the element.

With the hovered and picked up element changed events and the programmatic APIs on the ProgrammaticReticleTool a broad range of editing experiences can be implemented.

Tags

draw, edit, freehand, geometry editor, programmatic, reticle, sketch, vertex

Sample Code

EditGeometriesWithProgrammaticReticleTool.xaml EditGeometriesWithProgrammaticReticleTool.xaml EditGeometriesWithProgrammaticReticleTool.xaml.cs
<UserControl x:Class="ArcGIS.WPF.Samples.EditGeometriesWithProgrammaticReticleTool.EditGeometriesWithProgrammaticReticleTool"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:ArcGIS.WPF.Viewer.Converters"
xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013">
<UserControl.Resources>
<Style x:Key="IconStyle" TargetType="Button">
<Style.Setters>
<Setter Property="FontFamily" Value="{StaticResource CalciteUIIconsMediumFontFamily}" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Background" Value="White" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Padding" Value="3" />
<Setter Property="Margin" Value="3" />
</Style.Setters>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</Style.Triggers>
</Style>
<converters:BoolNegationConverter x:Key="BoolNegationConverter" />
</UserControl.Resources>
<Grid>
<esri:MapView x:Name="MyMapView" GeoViewTapped="MyMapView_GeoViewTapped" />
<Grid Margin="10"
HorizontalAlignment="Right"
VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="85" />
<ColumnDefinition Width="85" />
</Grid.ColumnDefinitions>
<Border Grid.Row="0"
Grid.ColumnSpan="2"
Margin="3,5"
Background="White">
<StackPanel>
<Label Content="Geometry type:" />
<ComboBox x:Name="GeometryTypePicker"
Grid.Row="1"
Grid.ColumnSpan="2"
Margin="5"
DisplayMemberPath="Key"
IsEnabled="{Binding GeometryEditor.IsStarted, ElementName=MyMapView, Converter={StaticResource BoolNegationConverter}}"
ToolTipService.ToolTip="Geometry types" />
</StackPanel>
</Border>
<Border Grid.Row="1"
Grid.ColumnSpan="2"
Margin="3,5"
Background="White">
<CheckBox x:Name="AllowVertexCreationCheckBox"
Margin="5"
Checked="AllowVertexCreationCheckBox_Checked"
Content="Allow vertex creation"
Unchecked="AllowVertexCreationCheckBox_Checked" />
</Border>
<Button x:Name="UndoButton"
Grid.Row="2"
Click="UndoButton_Click"
IsEnabled="False"
Style="{StaticResource IconStyle}"
ToolTipService.ToolTip="Undo"
Content="{StaticResource CalciteUIIcons_Glyph_Undo}" />
<Button Grid.Row="2"
Grid.Column="1"
Click="RedoButton_Click"
IsEnabled="{Binding GeometryEditor.CanRedo, ElementName=MyMapView}"
Style="{StaticResource IconStyle}"
ToolTipService.ToolTip="Redo"
Content="{StaticResource CalciteUIIcons_Glyph_Redo}" />
<Button Grid.Row="3"
Click="DeleteSelectedButton_Click"
IsEnabled="{Binding GeometryEditor.SelectedElement.CanDelete, ElementName=MyMapView, FallbackValue=False}"
Style="{StaticResource IconStyle}"
ToolTipService.ToolTip="Delete selected"
Content="{StaticResource CalciteUIIcons_Glyph_Erase}" />
<Button x:Name="SaveButton"
Grid.Row="3"
Grid.Column="1"
Click="SaveButton_Click"
IsEnabled="{Binding GeometryEditor.CanUndo, ElementName=MyMapView}"
Style="{StaticResource IconStyle}"
ToolTipService.ToolTip="Save edits"
Content="{StaticResource CalciteUIIcons_Glyph_CheckCircle}" />
<Button Grid.Row="4"
Click="DiscardButton_Click"
IsEnabled="{Binding GeometryEditor.IsStarted, ElementName=MyMapView}"
Style="{StaticResource IconStyle}"
ToolTipService.ToolTip="Discard edits"
Content="{StaticResource CalciteUIIcons_Glyph_CircleDisallowed}" />
<Button x:Name="MultifunctionButton"
Grid.Row="5"
Grid.ColumnSpan="2"
Height="30"
Margin="3"
Padding="3"
Click="MultifunctionButton_Click" />
</Grid>
</Grid>
</UserControl>