Exit condition for SketchEditor

1092
5
Jump to solution
08-12-2018 10:05 PM
JonasHashagen
New Contributor II

I'm currently facing the problem that I need to add an exit condition for sketching geometries using the SketchEditor. The sketch editor should be finished/completed as soon as the sketched geometry fullfills the condition (e.g. has exactly 4 points).

To achieve this I registered to the GeometryChanged event, check for the exit condition and call the CompleteCommand if it mets the condition:

private void SketchEditorOnGeometryChanged(object sender, GeometryChangedEventArgs e)
{
   if (this.CheckValidity(e.NewGeometry) && this.sketchEditor.CompleteCommand.CanExecute(null))
   {
      this.sketchEditor.CompleteCommand.Execute(null);
   }
}

However, the call to CompleteCommand will cause an NullReferenceException, because it will set the geometry of the SketchEditor to null, but the SketchEditor seems to use the value of geometry after the GeometryChanged event.

Am I missing something or is there no way to achieve such an exit condition?

Tags (1)
0 Kudos
1 Solution

Accepted Solutions
JenniferNery
Esri Regular Contributor

Oh that should not have happened, thank you for reporting this! I have logged an issue to fix NullRef exception.

The optional `drawAndEdit` parameter is to complete the task as soon as something is drawn. In the case of Polygon, after double-tap occurs and there's at least 3 vertices, it will be completed without going to edit mode or requiring Stop/Complete to be called.

Since you plan to complete the draw programmatically given your specific condition, you can alternatively use EditConfiguration to disable the edits you don't need, or

var config = new SketchEditConfiguration()
{
    AllowVertexEditing = false,
    AllowMove = false,
    AllowRotate = false,
    ResizeMode = SketchResizeMode.None
};
var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon, config);

you can change the symbols in the Style.

MyMapView.SketchEditor.Style.ShowNumbersForVertices = false;
MyMapView.SketchEditor.Style.SelectionColor = Color.Red;
MyMapView.SketchEditor.Style.SelectedVertexSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Red, 1);
MyMapView.SketchEditor.Style.VertexSymbol = null;
MyMapView.SketchEditor.Style.MidVertexSymbol = null;
var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon);

We still need to fix the NullRef ex but meanwhile you have the option to use any of the above suggestions.

View solution in original post

5 Replies
JenniferNery
Esri Regular Contributor

Whether you use CompleteCommand or Stop, SketchEditor.Geometry is expected to be cleared or set back to null since the SketchEditor.StartAsync would have already returned with resulting geometry. 


You probably have code similar to this. Geometry property or GeometryChanged are meant for tracking geometry as it gets created/updated. But it would be the result of StartAsync that gives you end geometry from the completed draw/edit.

MyMapView.Map = new Map(SpatialReferences.Wgs84);
MyMapView.GraphicsOverlays.Add(new GraphicsOverlay() { Renderer = new SimpleRenderer(new SimpleFillSymbol()) });

MyMapView.SketchEditor.GeometryChanged += (s, e) =>
{
    if ((e.NewGeometry as Polygon)?.Parts?.FirstOrDefault()?.PointCount == 4)
    {
        //if (MyMapView.SketchEditor.CompleteCommand.CanExecute(null))
        //{
        //    MyMapView.SketchEditor.CompleteCommand.Execute(null);
        //}
        MyMapView.SketchEditor.Stop();
          // SketchEditor.Geometry is null here
    }
};

MyMapView.SpatialReferenceChanged += async (s, e) =>
{
    var overlay = MyMapView.GraphicsOverlays.FirstOrDefault();

    try
    {                    
          // CompleteCommand or Stop will return resulting geometry here
        var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon);                         
        overlay.Graphics.Add(new Graphic(geom));
    }
    catch (TaskCanceledException) { }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, ex.GetType().Name);
    }

};

Another way to do this if awaiting StartAsync is not an option for you...

After checking you have at most 4 vertices and you know you will be completing the draw/edit, is to use SketchEditor.Geometry before CompleteCommand is executed or Stop is called.

JonasHashagen
New Contributor II

My code looks quite similiar and I believe I've spotted the minor difference that'll let my code break while yours does not. It's the call of StartAsync, because I'm using it with drawAndEdit == false.

var geometry = await this.MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon, false);

This leads to an exception being thrown:

   at Esri.ArcGISRuntime.UI.SketchEditor.Restart(Boolean forceRedraw)
   at Esri.ArcGISRuntime.UI.SketchEditor.AddPoint(MapPoint mapPoint)
   at Esri.ArcGISRuntime.UI.SketchEditor.<MapView_GeoViewTapped>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
[... async/threading related stuff ...]

This exception seems to get thrown asynchronously after the call to Stop. I've got the exception thrown directly after Stop and sometimes after I've got the geometry returned by StartAsync. Sadly, I have not been able to catch this exception and the whole application is going to crash. Both, the call to StartAsync and Stop are inside a try...catch block.

I've adjusted your sample so that it'll throw the exception.

MyMapView.Map = new Map(SpatialReferences.Wgs84);
MyMapView.GraphicsOverlays.Add(new GraphicsOverlay() { Renderer = new SimpleRenderer(new SimpleFillSymbol()) });

MyMapView.SketchEditor.GeometryChanged += (s, e) =>
{
    try
    {
        if ((e.NewGeometry as Polygon)?.Parts?.FirstOrDefault()?.PointCount == 4)
        {
            this.MyMapView.SketchEditor.Stop();
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, ex.GetType().Name);
    }
};

MyMapView.SpatialReferenceChanged += async (s, e) =>
{
    var overlay = MyMapView.GraphicsOverlays.FirstOrDefault();

    try
    {                    
          // CompleteCommand or Stop will return resulting geometry here
        var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon, false);                         
        overlay.Graphics.Add(new Graphic(geom));
    }
    catch (TaskCanceledException) { }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, ex.GetType().Name);
    }
};
0 Kudos
JenniferNery
Esri Regular Contributor

Oh that should not have happened, thank you for reporting this! I have logged an issue to fix NullRef exception.

The optional `drawAndEdit` parameter is to complete the task as soon as something is drawn. In the case of Polygon, after double-tap occurs and there's at least 3 vertices, it will be completed without going to edit mode or requiring Stop/Complete to be called.

Since you plan to complete the draw programmatically given your specific condition, you can alternatively use EditConfiguration to disable the edits you don't need, or

var config = new SketchEditConfiguration()
{
    AllowVertexEditing = false,
    AllowMove = false,
    AllowRotate = false,
    ResizeMode = SketchResizeMode.None
};
var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon, config);

you can change the symbols in the Style.

MyMapView.SketchEditor.Style.ShowNumbersForVertices = false;
MyMapView.SketchEditor.Style.SelectionColor = Color.Red;
MyMapView.SketchEditor.Style.SelectedVertexSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbolStyle.Circle, Color.Red, 1);
MyMapView.SketchEditor.Style.VertexSymbol = null;
MyMapView.SketchEditor.Style.MidVertexSymbol = null;
var geom = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Polygon);

We still need to fix the NullRef ex but meanwhile you have the option to use any of the above suggestions.

JonasHashagen
New Contributor II

Thanks for the workaround and adding an issue for this bug.

However you said:

The optional `drawAndEdit` parameter is to complete the task as soon as something is drawn. In the case of Polygon, after double-tap occurs and there's at least 3 vertices, it will be completed without going to edit mode or requiring Stop/Complete to be called.

This is currently not true. It is possible to get an invalid geometry returned if the user double clicks diractly after starting the sketch editor. This will create a polyline/polygon with just one point.

0 Kudos
JenniferNery
Esri Regular Contributor

I see, `drawAndEdit:false` completes when the expected gesture occurs (tap for Point, double-tap for Polyline/Polygon/ touch up for shapes drawn by drag) but it's CompleteCommand that checks for minimum set of vertices. We'll get this check added in here as well. There is already an existing issue logged for this. Thanks for clarification.

0 Kudos