How to use SketchEditor in a combined Rectangle and Point SketchCreationMode

1254
2
Jump to solution
02-20-2018 07:16 AM
MaximilianGlas
Esri Contributor

Hi,

I tried to write an Editing Workflow using the SketchEditor, where the user can select Features with the Rectangle drawing

(SketchCretionMode.Rectangle‍).

Everything is fine if the user draw a rectangle, the SketchEditor delivers the rectangle geometry as a result which I can use to select my features.

But, if the user decides to just select a single object by a click, this will not work with rectangle creation mode. The SketchEditor returns a null object in this case. By the way, this is the same for all SketchCreationModes with values 3 to 9.

I tried some workarounds to solve this, the best idea I had was to save the last click in the MapView in a local variable and - if the result of rectangle selection was null - to use this stored map point to select features.

private MapPoint _lastLocationClicked;

public MainWindow()
{
   MyMapView.GeoViewTapped += MyMapView_GeoViewTapped;
}

private void MyMapView_GeoViewTapped(object sender, Esri.ArcGISRuntime.UI.Controls.GeoViewInputEventArgs e)
{
    _lastLocationClicked = e.Location;
}

private async void Select_OnClick(object sender, RoutedEventArgs e)
{
    var creationMode =
        (SketchCreationMode) Enum.Parse(typeof(SketchCreationMode), EditingModeComboBox.SelectionBoxItem.ToString());
    Esri.ArcGISRuntime.Geometry.Geometry geometry =
        await MyMapView.SketchEditor.StartAsync(creationMode, false);

    MyMapView.SketchEditor.ClearGeometry();

    if (geometry != null)
    {
        var query = new QueryParameters() {Geometry = geometry};

        var selection = await MyMapView.Map.OperationalLayers.OfType<FeatureLayer>()
            .First()
            .SelectFeaturesAsync(query, SelectionMode.New);
    }
    else
    {
        if (creationMode == SketchCreationMode.Rectangle)
        {
            //add a scale dependent buffer
            var buffer = MyMapView.MapScale / 500;
            var bufferedGeometry = GeometryEngine.Buffer(_lastLocationClicked, buffer);
            var query = new QueryParameters() {Geometry = bufferedGeometry};

            var selection = await MyMapView.Map.OperationalLayers.OfType<FeatureLayer>()
                .First()
                .SelectFeaturesAsync(query, SelectionMode.New);
        }
        else
        {
            MyMapView.Map.OperationalLayers.OfType<FeatureLayer>()
                .First()
                .ClearSelection();
        }
    }
}

Of course, this is not a pretty way, so I have two questions:

  1. Is this the expected behavior, that the geometry returned is null in case of a single map click?
  2. Does anyone have a better idea how to allow both, rectangle and single point selection without enforcing the user to choice between this options manually?

Cheers

Max

0 Kudos
1 Solution

Accepted Solutions
JenniferNery
Esri Regular Contributor

Hi Max,

Thank you for your feedback. While it was intentional for geometry to be returned when mouse/touch is released for shapes drawn by drag (i.e. Arrow, Circle, Ellipse, Rectangle, FreehandLine, FreehandPolygon) when drawAndEdit=false and its expected complete gesture of mouse/touch up occurs, I can see how the behavior is in conflict with the other creation modes (i.e. Polyline, Polygon) which would have returned a multi-part geometry with shared vertices when its expected complete gesture of double tap occurs. The return type would still be dependent on the creation mode, which means we cannot return a MapPoint if Rectangle mode was used but we should probably return you a Polygon with shared vertices as the other two modes do. 

As for your specific use case, you should be able to do something like this which subscribes to GeoViewTapped event only when needed and use tapped location as fallback if the gesture did not result into a polygon.

I still logged an issue for consideration so we can be more consistent in returning geometry for all modes.

private async Task<Esri.ArcGISRuntime.Geometry.Geometry> GetSelectionGeometryAsync()
{ 
    MapPoint selectionPoint = null;
    EventHandler<GeoViewInputEventArgs> handler = (a, b) =>
    {
        selectionPoint = b.Location;
    };
    try
    {
        MyMapView.GeoViewTapped += handler;
        var geometry = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Rectangle, false);
        var selectionGeometry = geometry ?? selectionPoint;
        return geometry;
    }
    catch (TaskCanceledException) { }
    finally
    {
        MyMapView.GeoViewTapped -= handler;
    }
    return selectionPoint;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

2 Replies
JenniferNery
Esri Regular Contributor

Hi Max,

Thank you for your feedback. While it was intentional for geometry to be returned when mouse/touch is released for shapes drawn by drag (i.e. Arrow, Circle, Ellipse, Rectangle, FreehandLine, FreehandPolygon) when drawAndEdit=false and its expected complete gesture of mouse/touch up occurs, I can see how the behavior is in conflict with the other creation modes (i.e. Polyline, Polygon) which would have returned a multi-part geometry with shared vertices when its expected complete gesture of double tap occurs. The return type would still be dependent on the creation mode, which means we cannot return a MapPoint if Rectangle mode was used but we should probably return you a Polygon with shared vertices as the other two modes do. 

As for your specific use case, you should be able to do something like this which subscribes to GeoViewTapped event only when needed and use tapped location as fallback if the gesture did not result into a polygon.

I still logged an issue for consideration so we can be more consistent in returning geometry for all modes.

private async Task<Esri.ArcGISRuntime.Geometry.Geometry> GetSelectionGeometryAsync()
{ 
    MapPoint selectionPoint = null;
    EventHandler<GeoViewInputEventArgs> handler = (a, b) =>
    {
        selectionPoint = b.Location;
    };
    try
    {
        MyMapView.GeoViewTapped += handler;
        var geometry = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Rectangle, false);
        var selectionGeometry = geometry ?? selectionPoint;
        return geometry;
    }
    catch (TaskCanceledException) { }
    finally
    {
        MyMapView.GeoViewTapped -= handler;
    }
    return selectionPoint;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
MaximilianGlas
Esri Contributor

Thanks Jennifer, your solution is better, as it only takes into account the point input for the moment of recording. It should help for the moment, but if there will be a better support by the framework itself in future, I think this would be good.

0 Kudos