Hello,
After upgrading from ArcGIS Runtime 100.9 to 100.12, I can no longer delete features from a ServiceFeatureTable provided using a LocalServer.
More exactly, the code for deleting the feature executes just fine, the number of features in the feature table decreases, but if I zoom in/out, the deleted feature reappears.
I have stitched together a simple test app from the following ArcGIS Runtime Samples: Local Server Services, Feature Layer Selection, Delete Features (feature service)
The result is the same. When I tap a feature it gets deleted and the count decreases from 17 to 16. It stays at 16 while I move the map around, but once I zoom the feature pops back into existence and the feature count is 17.
Note: I have also tried using Esri.ArcGISRuntime.LocalServices version 100.9 in combination with Esri.ArcGISRuntime 100.12 or 100.11, but had the same results.
using Esri.ArcGISRuntime;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.LocalServices;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI.Controls;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApp1 {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
LocalFeatureService _localFeatureService;
FeatureLayer _featureLayer;
public MainWindow() {
InitializeComponent();
Initialize();
}
private async void Initialize() {
// Create a map and add it to the view
MyMapView.Map = new Map(Basemap.CreateImagery());
try {
// LocalServer must not be running when setting the data path.
if (LocalServer.Instance.Status == LocalServerStatus.Started) {
await LocalServer.Instance.StopAsync();
}
// Set the local data path - must be done before starting. On most systems, this will be C:\EsriSamples\AppData.
// This path should be kept short to avoid Windows path length limitations.
string tempDataPathRoot = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.Windows)).FullName;
string tempDataPath = System.IO.Path.Combine(tempDataPathRoot, "EsriSamples", "AppData");
Directory.CreateDirectory(tempDataPath); // CreateDirectory won't overwrite if it already exists.
LocalServer.Instance.AppDataPath = tempDataPath;
// Start the local server instance
await LocalServer.Instance.StartAsync();
} catch (Exception ex) {
var localServerTypeInfo = typeof(LocalMapService).GetTypeInfo();
var localServerVersion = FileVersionInfo.GetVersionInfo(localServerTypeInfo.Assembly.Location);
MessageBox.Show($"Please ensure that local server {localServerVersion.FileVersion} is installed prior to using the sample. The download link is in the description. Message: {ex.Message}", "Local Server failed to start");
return;
}
// Load the sample data and get the path
string myfeatureServicePath = GetFeatureLayerPath();
// Create the feature service to serve the local data
_localFeatureService = new LocalFeatureService(myfeatureServicePath);
// Listen to feature service status changes
_localFeatureService.StatusChanged += _localFeatureService_StatusChanged;
// Start the feature service
try {
await _localFeatureService.StartAsync();
} catch (Exception ex) {
MessageBox.Show(ex.Message, "The feature service failed to load");
}
}
private async void _localFeatureService_StatusChanged(object sender, StatusChangedEventArgs e) {
// Load the map from the service once ready
if (e.Status == LocalServerStatus.Started) {
// Get the path to the first layer - the local feature service url + layer ID
string layerUrl = _localFeatureService.Url + "/0";
// Create the ServiceFeatureTable
ServiceFeatureTable myFeatureTable = new ServiceFeatureTable(new Uri(layerUrl));
// Create the Feature Layer from the table
_featureLayer = new FeatureLayer(myFeatureTable);
// Add the layer to the map
MyMapView.Map.OperationalLayers.Add(_featureLayer);
try {
// Wait for the layer to load
await _featureLayer.LoadAsync();
// Set the viewpoint on the MapView to show the layer data
await MyMapView.SetViewpointGeometryAsync(_featureLayer.FullExtent, 50);
MyMapView.GeoViewTapped += OnMapViewTapped;
} catch (Exception ex) {
MessageBox.Show(ex.ToString(), "Error");
}
}
}
private async void OnMapViewTapped(object sender, GeoViewInputEventArgs e) {
try {
// Define the selection tolerance.
double tolerance = 15;
// Convert the tolerance to map units.
double mapTolerance = tolerance * MyMapView.UnitsPerPixel;
// Get the tapped point.
MapPoint geometry = e.Location;
// Normalize the geometry if wrap-around is enabled.
// This is necessary because of how wrapped-around map coordinates are handled by Runtime.
// Without this step, querying may fail because wrapped-around coordinates are out of bounds.
if (MyMapView.IsWrapAroundEnabled) {
geometry = (MapPoint)GeometryEngine.NormalizeCentralMeridian(geometry);
}
// Define the envelope around the tap location for selecting features.
Envelope selectionEnvelope = new Envelope(geometry.X - mapTolerance, geometry.Y - mapTolerance, geometry.X + mapTolerance,
geometry.Y + mapTolerance, MyMapView.Map.SpatialReference);
// Define the query parameters for selecting features.
QueryParameters queryParams = new QueryParameters
{
// Set the geometry to selection envelope for selection by geometry.
Geometry = selectionEnvelope
};
// Select the features based on query parameters defined above.
ServiceFeatureTable table = (ServiceFeatureTable)_featureLayer.FeatureTable;
long featureCountOld = table.NumberOfFeatures;
bool deletedStuff = false;
var results = await _featureLayer.SelectFeaturesAsync(queryParams, Esri.ArcGISRuntime.Mapping.SelectionMode.New);
foreach (var feature in results) {
// delete feature from feature table
await table.DeleteFeatureAsync(feature);
// Sync the change with the service.
await table.ApplyEditsAsync();
deletedStuff = true;
}
long featureCountNew = table.NumberOfFeatures;
if (deletedStuff) {
MessageBox.Show($"Deleted features, feature count changed from {featureCountOld} to {featureCountNew}");
} else {
MessageBox.Show($"Nothing deleted, feature count is {featureCountOld}");
}
} catch (Exception ex) {
MessageBox.Show(ex.ToString(), "Error");
}
}
private static string GetFeatureLayerPath() {
return @"D:\PointsofInterest.mpkx";
}
}
}