I have a problem with the sketchEditor in WPF when I create a rectangle or a circle. I take the example of the ESRI site. one time out of 2, it draws the shape. and the other time not, but the map moves. Obliged to click once more to be able to redraw.
SketchCreationMode creationMode = (SketchCreationMode)SketchModeComboBox.SelectedItem;
geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);
Have you encountered this issue before?
Solved! Go to Solution.
I made a modified version of the WPF sample. I added an event handler for a right click that completes the current sketch and starts a new one. You can start drawing the next shape without moving the map.
Please share more of your code so I can understand your issue better.
Zack
// Copyright 2017 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Point = System.Windows.Point;
namespace ArcGISRuntime.WPF.Samples.SketchOnMap
{
[ArcGISRuntime.Samples.Shared.Attributes.Sample(
name: "Sketch on map",
category: "GraphicsOverlay",
description: "Use the Sketch Editor to edit or sketch a new point, line, or polygon geometry on to a map.",
instructions: "Choose which geometry type to sketch from one of the available buttons. Choose from points, multipoints, polylines, polygons, freehand polylines, and freehand polygons.",
tags: new[] { "draw", "edit" })]
public partial class SketchOnMap
{
// Graphics overlay to host sketch graphics
private GraphicsOverlay _sketchOverlay;
public SketchOnMap()
{
InitializeComponent();
// Call a function to set up the map and sketch editor
Initialize();
}
private void Initialize()
{
// Create a light gray canvas map
Map myMap = new Map(Basemap.CreateLightGrayCanvas());
// Create graphics overlay to display sketch geometry
_sketchOverlay = new GraphicsOverlay();
MyMapView.GraphicsOverlays.Add(_sketchOverlay);
// Assign the map to the MapView
MyMapView.Map = myMap;
// Fill the combo box with choices for the sketch modes (shapes)
SketchModeComboBox.ItemsSource = System.Enum.GetValues(typeof(SketchCreationMode));
SketchModeComboBox.SelectedIndex = 0;
// Set the sketch editor as the page's data context
DataContext = MyMapView.SketchEditor;
}
#region Graphic and symbol helpers
private Graphic CreateGraphic(Esri.ArcGISRuntime.Geometry.Geometry geometry)
{
// Create a graphic to display the specified geometry
Symbol symbol = null;
switch (geometry.GeometryType)
{
// Symbolize with a fill symbol
case GeometryType.Envelope:
case GeometryType.Polygon:
{
symbol = new SimpleFillSymbol()
{
Color = Color.Red,
Style = SimpleFillSymbolStyle.Solid
};
break;
}
// Symbolize with a line symbol
case GeometryType.Polyline:
{
symbol = new SimpleLineSymbol()
{
Color = Color.Red,
Style = SimpleLineSymbolStyle.Solid,
Width = 5d
};
break;
}
// Symbolize with a marker symbol
case GeometryType.Point:
case GeometryType.Multipoint:
{
symbol = new SimpleMarkerSymbol()
{
Color = Color.Red,
Style = SimpleMarkerSymbolStyle.Circle,
Size = 15d
};
break;
}
}
// pass back a new graphic with the appropriate symbol
return new Graphic(geometry, symbol);
}
private async Task<Graphic> GetGraphicAsync()
{
// Wait for the user to click a location on the map
Geometry mapPoint = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Point, false);
// Convert the map point to a screen point
Point screenCoordinate = MyMapView.LocationToScreen((MapPoint)mapPoint);
// Identify graphics in the graphics overlay using the point
IReadOnlyList<IdentifyGraphicsOverlayResult> results = await MyMapView.IdentifyGraphicsOverlaysAsync(screenCoordinate, 2, false);
// If results were found, get the first graphic
Graphic graphic = null;
IdentifyGraphicsOverlayResult idResult = results.FirstOrDefault();
if (idResult != null && idResult.Graphics.Count > 0)
{
graphic = idResult.Graphics.FirstOrDefault();
}
// Return the graphic (or null if none were found)
return graphic;
}
#endregion Graphic and symbol helpers
private void DrawButtonClick(object sender, RoutedEventArgs e)
{
Draw();
}
private async void Draw()
{
try
{
// Let the user draw on the map view using the chosen sketch mode
SketchCreationMode creationMode = (SketchCreationMode)SketchModeComboBox.SelectedItem;
Esri.ArcGISRuntime.Geometry.Geometry geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);
// Create and add a graphic from the geometry the user drew
Graphic graphic = CreateGraphic(geometry);
_sketchOverlay.Graphics.Add(graphic);
// Enable/disable the clear and edit buttons according to whether or not graphics exist in the overlay
ClearButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
EditButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
}
catch (TaskCanceledException)
{
// Ignore ... let the user cancel drawing
}
catch (Exception ex)
{
// Report exceptions
MessageBox.Show("Error drawing graphic shape: " + ex.Message);
}
}
private void ClearButtonClick(object sender, RoutedEventArgs e)
{
// Remove all graphics from the graphics overlay
_sketchOverlay.Graphics.Clear();
// Disable buttons that require graphics
ClearButton.IsEnabled = false;
EditButton.IsEnabled = false;
}
private async void EditButtonClick(object sender, RoutedEventArgs e)
{
try
{
// Allow the user to select a graphic
Graphic editGraphic = await GetGraphicAsync();
if (editGraphic == null) { return; }
// Let the user make changes to the graphic's geometry, await the result (updated geometry)
Esri.ArcGISRuntime.Geometry.Geometry newGeometry = await MyMapView.SketchEditor.StartAsync(editGraphic.Geometry);
// Display the updated geometry in the graphic
editGraphic.Geometry = newGeometry;
}
catch (TaskCanceledException)
{
// Ignore ... let the user cancel editing
}
catch (Exception ex)
{
// Report exceptions
MessageBox.Show("Error editing shape: " + ex.Message);
}
}
private void MyMapView_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(MyMapView.SketchEditor.CompleteCommand.CanExecute(null))
{
MyMapView.SketchEditor.CompleteCommand.Execute(null);
e.Handled = true;
Draw();
}
}
}
}
<UserControl
x:Class="ArcGISRuntime.WPF.Samples.SketchOnMap.SketchOnMap"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="500"
d:DesignWidth="600"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<esri:MapView
x:Name="MyMapView"
Grid.Column="1"
MouseRightButtonUp="MyMapView_MouseRightButtonUp" />
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="20" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="20" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="Sketch shape:" />
<ComboBox
x:Name="SketchModeComboBox"
Grid.Row="1"
Grid.Column="1"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" />
<Button
Grid.Row="2"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="DrawButtonClick"
Content="Draw" />
<Button
x:Name="EditButton"
Grid.Row="3"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="EditButtonClick"
Content="Edit"
IsEnabled="False" />
<StackPanel
Grid.Row="5"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Width="50"
Height="25"
Margin="5"
Command="{Binding UndoCommand}"
Content="Undo" />
<Button
Width="50"
Height="25"
Margin="5"
Command="{Binding RedoCommand}"
Content="Redo" />
</StackPanel>
<Button
Grid.Row="6"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Command="{Binding CompleteCommand}"
Content="Complete" />
<Button
Grid.Row="8"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Command="{Binding CancelCommand}"
Content="Cancel" />
<Button
x:Name="ClearButton"
Grid.Row="9"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="ClearButtonClick"
Content="Clear"
IsEnabled="False" />
</Grid>
</Grid>
</UserControl>
May be that :
MyMapView.SketchEditor.CompleteCommand.CanExecute(null)
but not working. I deleted Complet Button. I finish shaping by right click only
When drawAndEdit parameter is true as in your code snippet, after the drawing a shape it will go to edit mode and wait for Complete command. If you wanted to complete draw as soon as you release the mouse/touch, you'd want drawAndEdit=false for shapes like Arrow, Circle, Ellipse, FreehandLine, FreehandPolygon.
You can try the following sample and toggle the value for drawAndEdit, use the Complete/Cancel buttons to end draw/edit mode. Another way is to call MyMapView.SketchEditor.StopAsync() at any time which will also complete the draw/edit.
<Grid>
<esri:MapView x:Name="MyMapView" />
<StackPanel VerticalAlignment="Top"
HorizontalAlignment="Right"
Orientation="Horizontal">
<ComboBox x:Name="DrawModes" />
<CheckBox x:Name="DrawAndEdit"
Content="DrawAndEdit"
IsChecked="False" />
<Button Content="Draw"
Click="OnDraw" />
<Button Content="Complete"
Command="{Binding ElementName=MyMapView, Path=SketchEditor.CompleteCommand}" />
<Button Content="Cancel"
Command="{Binding ElementName=MyMapView, Path=SketchEditor.CancelCommand}" />
</StackPanel>
</Grid>
public MainWindow()
{
InitializeComponent();
DrawModes.ItemsSource = Enum.GetValues(typeof(SketchCreationMode));
MyMapView.Map = new Map(Basemap.CreateTopographicVector());
MyMapView.GraphicsOverlays.Add(new GraphicsOverlay());
}
private SimpleFillSymbol _fillSymbol = new SimpleFillSymbol(SimpleFillSymbolStyle.Solid, Color.Blue, null);
private async void OnDraw(object sender, RoutedEventArgs e)
{
try
{
var drawAndEdit = DrawAndEdit.IsChecked.HasValue && DrawAndEdit.IsChecked.Value;
if (DrawModes.SelectedItem is SketchCreationMode creationMode)
{
var geometry = await MyMapView.SketchEditor.StartAsync(creationMode, drawAndEdit);
MyMapView.GraphicsOverlays[0].Graphics.Add(new Graphic(geometry, _fillSymbol));
}
}
catch (TaskCanceledException) { }
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.GetType().Name);
}
}
}
Thank you for your response; SketchEditor has no StopAsync() members ... And I don't want to use a CompleteCommand.CanExecute button. I want to do everything with the mouse. As soon as I right click, I activate a method that validates and calls
if (MyMapView.SketchEditor.CompleteCommand.CanExecute(null))
{
// Finish the sketch.
MyMapView.SketchEditor.CompleteCommand.Execute(null);
e.Handled = true;
drawEdit = true; //Personal method
}
But it doesn't work. I have to move the map to be able to redraw it again.
It takes me out of shape editing.
It's a problem between actions on the map and the creation of shapes.
I made a modified version of the WPF sample. I added an event handler for a right click that completes the current sketch and starts a new one. You can start drawing the next shape without moving the map.
Please share more of your code so I can understand your issue better.
Zack
// Copyright 2017 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Point = System.Windows.Point;
namespace ArcGISRuntime.WPF.Samples.SketchOnMap
{
[ArcGISRuntime.Samples.Shared.Attributes.Sample(
name: "Sketch on map",
category: "GraphicsOverlay",
description: "Use the Sketch Editor to edit or sketch a new point, line, or polygon geometry on to a map.",
instructions: "Choose which geometry type to sketch from one of the available buttons. Choose from points, multipoints, polylines, polygons, freehand polylines, and freehand polygons.",
tags: new[] { "draw", "edit" })]
public partial class SketchOnMap
{
// Graphics overlay to host sketch graphics
private GraphicsOverlay _sketchOverlay;
public SketchOnMap()
{
InitializeComponent();
// Call a function to set up the map and sketch editor
Initialize();
}
private void Initialize()
{
// Create a light gray canvas map
Map myMap = new Map(Basemap.CreateLightGrayCanvas());
// Create graphics overlay to display sketch geometry
_sketchOverlay = new GraphicsOverlay();
MyMapView.GraphicsOverlays.Add(_sketchOverlay);
// Assign the map to the MapView
MyMapView.Map = myMap;
// Fill the combo box with choices for the sketch modes (shapes)
SketchModeComboBox.ItemsSource = System.Enum.GetValues(typeof(SketchCreationMode));
SketchModeComboBox.SelectedIndex = 0;
// Set the sketch editor as the page's data context
DataContext = MyMapView.SketchEditor;
}
#region Graphic and symbol helpers
private Graphic CreateGraphic(Esri.ArcGISRuntime.Geometry.Geometry geometry)
{
// Create a graphic to display the specified geometry
Symbol symbol = null;
switch (geometry.GeometryType)
{
// Symbolize with a fill symbol
case GeometryType.Envelope:
case GeometryType.Polygon:
{
symbol = new SimpleFillSymbol()
{
Color = Color.Red,
Style = SimpleFillSymbolStyle.Solid
};
break;
}
// Symbolize with a line symbol
case GeometryType.Polyline:
{
symbol = new SimpleLineSymbol()
{
Color = Color.Red,
Style = SimpleLineSymbolStyle.Solid,
Width = 5d
};
break;
}
// Symbolize with a marker symbol
case GeometryType.Point:
case GeometryType.Multipoint:
{
symbol = new SimpleMarkerSymbol()
{
Color = Color.Red,
Style = SimpleMarkerSymbolStyle.Circle,
Size = 15d
};
break;
}
}
// pass back a new graphic with the appropriate symbol
return new Graphic(geometry, symbol);
}
private async Task<Graphic> GetGraphicAsync()
{
// Wait for the user to click a location on the map
Geometry mapPoint = await MyMapView.SketchEditor.StartAsync(SketchCreationMode.Point, false);
// Convert the map point to a screen point
Point screenCoordinate = MyMapView.LocationToScreen((MapPoint)mapPoint);
// Identify graphics in the graphics overlay using the point
IReadOnlyList<IdentifyGraphicsOverlayResult> results = await MyMapView.IdentifyGraphicsOverlaysAsync(screenCoordinate, 2, false);
// If results were found, get the first graphic
Graphic graphic = null;
IdentifyGraphicsOverlayResult idResult = results.FirstOrDefault();
if (idResult != null && idResult.Graphics.Count > 0)
{
graphic = idResult.Graphics.FirstOrDefault();
}
// Return the graphic (or null if none were found)
return graphic;
}
#endregion Graphic and symbol helpers
private void DrawButtonClick(object sender, RoutedEventArgs e)
{
Draw();
}
private async void Draw()
{
try
{
// Let the user draw on the map view using the chosen sketch mode
SketchCreationMode creationMode = (SketchCreationMode)SketchModeComboBox.SelectedItem;
Esri.ArcGISRuntime.Geometry.Geometry geometry = await MyMapView.SketchEditor.StartAsync(creationMode, true);
// Create and add a graphic from the geometry the user drew
Graphic graphic = CreateGraphic(geometry);
_sketchOverlay.Graphics.Add(graphic);
// Enable/disable the clear and edit buttons according to whether or not graphics exist in the overlay
ClearButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
EditButton.IsEnabled = _sketchOverlay.Graphics.Count > 0;
}
catch (TaskCanceledException)
{
// Ignore ... let the user cancel drawing
}
catch (Exception ex)
{
// Report exceptions
MessageBox.Show("Error drawing graphic shape: " + ex.Message);
}
}
private void ClearButtonClick(object sender, RoutedEventArgs e)
{
// Remove all graphics from the graphics overlay
_sketchOverlay.Graphics.Clear();
// Disable buttons that require graphics
ClearButton.IsEnabled = false;
EditButton.IsEnabled = false;
}
private async void EditButtonClick(object sender, RoutedEventArgs e)
{
try
{
// Allow the user to select a graphic
Graphic editGraphic = await GetGraphicAsync();
if (editGraphic == null) { return; }
// Let the user make changes to the graphic's geometry, await the result (updated geometry)
Esri.ArcGISRuntime.Geometry.Geometry newGeometry = await MyMapView.SketchEditor.StartAsync(editGraphic.Geometry);
// Display the updated geometry in the graphic
editGraphic.Geometry = newGeometry;
}
catch (TaskCanceledException)
{
// Ignore ... let the user cancel editing
}
catch (Exception ex)
{
// Report exceptions
MessageBox.Show("Error editing shape: " + ex.Message);
}
}
private void MyMapView_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(MyMapView.SketchEditor.CompleteCommand.CanExecute(null))
{
MyMapView.SketchEditor.CompleteCommand.Execute(null);
e.Handled = true;
Draw();
}
}
}
}
<UserControl
x:Class="ArcGISRuntime.WPF.Samples.SketchOnMap.SketchOnMap"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="500"
d:DesignWidth="600"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<esri:MapView
x:Name="MyMapView"
Grid.Column="1"
MouseRightButtonUp="MyMapView_MouseRightButtonUp" />
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="20" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition Height="20" />
<RowDefinition Height="35" />
<RowDefinition Height="35" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Text="Sketch shape:" />
<ComboBox
x:Name="SketchModeComboBox"
Grid.Row="1"
Grid.Column="1"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" />
<Button
Grid.Row="2"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="DrawButtonClick"
Content="Draw" />
<Button
x:Name="EditButton"
Grid.Row="3"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="EditButtonClick"
Content="Edit"
IsEnabled="False" />
<StackPanel
Grid.Row="5"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Width="50"
Height="25"
Margin="5"
Command="{Binding UndoCommand}"
Content="Undo" />
<Button
Width="50"
Height="25"
Margin="5"
Command="{Binding RedoCommand}"
Content="Redo" />
</StackPanel>
<Button
Grid.Row="6"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Command="{Binding CompleteCommand}"
Content="Complete" />
<Button
Grid.Row="8"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Command="{Binding CancelCommand}"
Content="Cancel" />
<Button
x:Name="ClearButton"
Grid.Row="9"
Grid.Column="1"
Width="100"
Height="25"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Click="ClearButtonClick"
Content="Clear"
IsEnabled="False" />
</Grid>
</Grid>
</UserControl>
1000 thanks Zack. Your method works wonderfully. The problem is solved 🙂
What version of ArcGIS Runtime SDK for .NET are you using? There should be a Stop which may be less awkward to call in code than Complete command but they function the same. Could it be possible that StartAsync for the next draw is triggered, maybe events are stepping on each other? You can also check SketchEditor.IsEnabled and SketchEditor.Geometry?.IsEmpty() == false to know that something is actively being drawn/edited. You can put breakpoint where `catch(TaskCanceledException){}` is handled or where you have any StartAsync call to see if maybe another session cancels the draw.
Hi . My version is v100.9.0 Esri.ArcGISRuntime.WPF and yes there is one Stop() on MyMapView.SketchEditor.Stop();
I make that also.
The problem is solved with the method cited by Zack above