Skip To Content ArcGIS for Developers Sign In Dashboard

Edit features

You can let users edit features while online (connected) or offline (disconnected). Editing includes adding new features, deleting features, and updating existing features by changing their geometry (location or shape), attributes, or attachments. There are two models for editing features: feature table editing and feature layer editing. This topic focuses on feature table editing. For an introduction to editing and the editing models, see Editing.

Whether you are online or offline, the workflow to edit features is similar. In both cases, you need to do the following:

  1. Create a feature table—In a connected workflow, create it from a feature service. In a disconnected workflow, create it from a geodatabase you generated with a sync-enabled feature service before you went offline, as described in Create an offline map.
  2. Create a feature layer from the feature table and add the layer to the map.
  3. Perform any edits against the feature table (add, update, and delete features and feature attachments).
  4. Commit your edits—In a connected workflow, apply any edits you make to the feature service right away. In a disconnected workflow, sync all your edits back to the service once you have a network connection, as described in Sync offline edits.

In a connected workflow, the type of feature table you create and edit is a ServiceFeatureTable. In a disconnected workflow, the type of feature table you create and edit is a GeodatabaseFeatureTable. Both of these classes are types of ArcGISFeatureTable. The class hierarchy between these is as follows:

Relationship of feature table classes

To update or delete features, your app should enable users to select features on the map, as described below in Select features.

Create a feature table

Before you can edit features, you need to obtain feature data from a feature service. In an online workflow, create a feature table from a feature service right before you want to edit features, for example, on application load. In an offline workflow, generate a geodatabase from a sync-enabled feature service while you have a network connection, in preparation for editing features offline. When offline, create feature tables from the geodatabase to edit the features locally. In both cases, check the capabilities of the feature service to ensure the editing capability is available.


In an online workflow, create a geodatabase feature service table (ServiceFeatureTable class) from a feature service. You can then create a feature layer using this feature table. Once you add the feature layer to a map, features in the map extent are added to the feature service table and can be edited. As you pan and zoom the map (that is, change the map extent), more features are retrieved from the feature service and added to the geodatabase feature service table.


The number of features you see when you initially visit a new area of the map is limited by the feature service's MaxRecordCount property (the default value for this property is 1,000). Pan and zoom to query the service for more features. Once features are retrieved from the service and visible in your map, they are available in your geodatabase feature service table for editing and querying.

If you define a FeatureLayer using XAML, the underlying ServiceFeatureTable will be projected to align with the spatial reference defined for the containing MapView. When initializing a ServiceFeatureTable instance in your code, however, you can optionally pass in a spatial reference for the table. If you do not explicitly set the spatial reference when initializing the ServiceFeatureTable, the spatial reference of the service will be used. Be aware that if your map is in a different spatial reference than the default spatial reference of your ServiceFeatureTable, your features will not appear on the map. When possible, it's therefore a good practice to set the spatial reference explicitly.

The following example illustrates creating feature layers using XAML. The ServiceFeatureTable used for each layer will be automatically projected to the spatial reference of the map view (defined by the basemap layer).

<esri:MapView x:Name="MyMapView">
    <esri:FeatureLayer ID="MarineOnline">
    <esri:FeatureLayer ID="BirdsOnline">

The example below illustrates creating a feature layer using code. The spatial reference for the ServiceFeatureTable is set by passing the spatial reference of the map view as the optional argument. This ensures that the features will display on the map as expected.

// create a new geodatabase feature service table; point to a feature service layer end point
var table = new ServiceFeatureTable();
table.ServiceUri = "";

// include all fields in the OutFields property to ensure they're returned by queries and available for editing
table.OutFields = Esri.ArcGISRuntime.Tasks.Query.OutFields.All;

// NOTE: you can restrict the output fields with code like the following ...
//var myOutFields = new Esri.ArcGISRuntime.Tasks.Query.OutFields();
//table.OutFields = myOutFields;

// initialize the feature table; use the map view's spatial reference for the optional "sr_override" argument
await table.InitializeAsync(MyMapView.SpatialReference);

// if the table was initialized successfully, create a new feature layer for the table and add it to the map
if (table.IsInitialized)
    var lyr = new FeatureLayer
        ID = "Birds",
        DisplayName = "Bird Observations",
        FeatureTable = table


The static method ServiceFeatureTable.OpenAsync can also be used to instantiate a new ServiceFeatureTable with a specified spatial reference.


Make sure to include all the fields you'll need in the OutFields property. You will not be able to query or edit attribute values for fields you do not include.


In an offline workflow, generate a geodatabase from a sync-enabled feature service while you have a network connection. Follow the geodatabase generation process described in Create an offline map. This process results in a geodatabase stored locally on disk. The geodatabase contains one or more feature tables, one for each service layer or service table that you requested in the geodatabase generation process. When offline, create geodatabase feature tables (GeodatabaseFeatureTable class) from the geodatabase, for example, on application load. The features in the geodatabase feature tables are available for editing whether you create a feature layer or not, but in most cases you'll want to create a feature layer from the feature tables to display the features on a map. Also, consider generating an offline basemap to give the feature data some geographical context when your users edit offline, as described in Include a basemap.

The following code sample shows how to create a feature table from a table in a local geodatabase:

// open a local geodatabase
var gdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(@"C:\data\localdata.geodatabase");

// get the first table in the database
var table = gdb.FeatureTables.FirstOrDefault();

// get the third table
var anotherTable = gdb.FeatureTables.ElementAt(2);

// find a table by name
var marineTable = gdb.FeatureTables.FirstOrDefault(t => t.Name == "Marine");

// loop through all tables
foreach (var t in gdb.FeatureTables)
    // ... code here to work with the table ...

Add layers to the map

Display the features contained in the feature table in a map so your users can view and edit them. Create a feature layer from the feature table and add the layer to a map. The feature layer, once added to a map, takes care of displaying the features contained in your feature table that fall within the map extent displayed. When you make edits to features in the table, these edits are visible right away in the associated feature layer and map, but not yet committed back to the service.

The following code sample shows how to create a feature layer from a feature table:

// create and add feature layers from local GDB ...
var geodatabasePath = @"C:\Data\wetlands.geodatabase";

// open the local geodatabase
var gdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(geodatabasePath);

// loop thru all tables in the database
foreach (var table in gdb.FeatureTables)
    // create a new feature layer for each table
    var lyr = new FeatureLayer
        ID = table.Name + "_Offline",
        DisplayName = table.Name,
        FeatureTable = table

    // add the layer to the map

Add features

To insert a new feature into a geodatabase table, call the AddAsync method, which is overloaded to accept either a Feature object (created using the appropriate geodatabase table schema), or the geometry and attributes you want to store. This method returns the unique feature ID of the added feature, which you can use if you need to modify the feature later on. Adding a feature to a geodatabase table is shown in the code below:

// get a point from the user
var mapPoint = await MyMapView.Editor.RequestPointAsync();
// open the local geodatabase
var gdb = await Esri.ArcGISRuntime.Data.Geodatabase.OpenAsync(geodatabasePath);

// open the "Marine" table and create a new feature using its schema
var gdbTable = gdb.FeatureTables.FirstOrDefault(t => t.Name == "Marine");
var newFeature = new Esri.ArcGISRuntime.Data.GeodatabaseFeature(gdbTable.Schema);

// assign the point from the user as the feature's geometry
newFeature.Geometry = mapPoint;

// get the attributes from the feature (a Dictionary<string, object>) and set some values
var attributes = newFeature.Attributes;  
attributes["type"] = 1; // Coded value domain, 1='Manatee'
attributes["confirmed"] = 1; // 0=NO, 1=YES
attributes["comments"] = "EM 11 Survey Team";

// add the new feature to the table, the OID of the new feature is returned
var recNo = await gdbTable.AddAsync(newFeature);

Update features

Features can be updated with the UpdateAsync method on the GeodatabaseFeatureTable.

The code sample below shows a method that updates a point feature in the geodatabase feature table with a new point geometry, changing its location on the map.

// create a list of the record IDs to update (just one in this case)
var idList = new List<long> { this.lastAddedOid };

// query the table for the features with the specified IDs
var updateFeatures = await gdbTable.QueryAsync(idList);

// get the first GeodatabaseFeature (should be one or zero)
var feature = updateFeatures.FirstOrDefault();
if (feature == null) { return; }

// update the feature's geometry with a new point
feature.Geometry = newPoint;

// update one of the attribute values
feature.Attributes["comments"] = "point updated to last known location";

// commit the updated feature to the GeodatabaseTable
await gdbTable.UpdateAsync(feature);

Delete features

Features can be deleted from a local GeodatabaseFeatureTable by calling the DeleteAsync method. This method is overloaded to allow you to specify the features you want to delete in several ways. To delete a single feature, you can pass in either the GeodatabaseFeature itself or only its feature ID. To delete several features, you can specify a list (IEnumerable<long>) of IDs for the features you want to delete. This is especially useful for deleting the current set of selected features in a FeatureLayer, which can be returned using the SelectedFeatureIDs property. The following example illustrates calling DeleteAsync with a list of feature IDs.

var lyr = MyMapView.Map.Layers["MyFeatureLayer"] as Esri.ArcGISRuntime.Layers.FeatureLayer;
var selectedIds = lyr.SelectedFeatureIDs;
await gdbTable.DeleteAsync(selectedIds);

Select features

In a typical map application involving editing, users should be able to select features they want to edit. You can programmatically select features in a feature layer by passing a set of feature IDs to the SelectFeatures method on FeatureLayer. You typically obtain feature IDs by performing a query on the geodatabase table from which the feature layer was created, or by letting your users click the map and obtain the IDs of any features within a certain pixel tolerance around the clicked point. The following code sample shows how to use a touch event listener on the map to select clicked features:

private async void MyMapView_TouchUp(object sender, TouchEventArgs e)
    // get the layer you want to select from (FeatureLayer)
    var lyr = MyMapView.Map.Layers["MarineOffline"] as FeatureLayer;
    if (lyr == null) { return; }

    // use HitTestAsync to get feature IDs for the location touched
    var featureIDs = await lyr.HitTestAsync(MyMapView, e.GetTouchPoint(MyMapView).Position);

    // select the features in the layer

Commit your edits

Committing your feature table edits to the feature service is different depending on whether your workflow is fully connected or disconnected.


In a fully connected workflow, you should apply feature edits and attachment edits back to the service as you make them. That way, anyone else using the same feature service will have access to your changes right away.

To commit your feature edits to the service, call the ApplyEditsAsync method on ServiceFeatureTable. Pass in true to require all edits to succeed in order to be committed, or false to commit edits individually. You can get the count of current feature edits using AddedFeaturesCount, UpdatedFeaturesCount, and DeletedFeaturesCount. This indicates the number of features that will be committed to the service upon calling ApplyEditsAsync.

The ApplyEditsAsync method returns a FeatureEditResult object. This object has properties for getting information about individual feature edits that were attempted on the server as a result of the call: AddResults, UpdateResults, and DeleteResults. Each of these properties returns a read-only list of FeatureEditResultItem that provides the object ID, global ID, success flag, and error details (if an edit failed).

The following example shows applying edits to the server and then evaluating the result.

// store the count of edits that need to be applied to the server
var totalAdds = table.AddedFeaturesCount;
var totalUpdates = table.UpdatedFeaturesCount;
var totalDeletes = table.DeletedFeaturesCount;

// apply edits, get the edit result
var editResult = await table.ApplyEditsAsync(false);

// count successful feature edits
var added = 0;
var updated = 0;
var deleted = 0;

// loop through all add results, count success
foreach (var add in editResult.AddResults)
    if (add.Success) { added++; }
// loop through all update results, count success
foreach (var update in editResult.UpdateResults)
    if (update.Success) { updated++; }
// loop through all delete results, count success
foreach (var delete in editResult.DeleteResults)
    if (delete.Success) { deleted++; }
// report edit status
var msg = new StringBuilder();
msg.AppendLine("Successfully added " + added.ToString() + " features of " + totalAdds.ToString() + " attempted.");
msg.AppendLine("Successfully updated " + updated.ToString() + " features of " + totalUpdates.ToString() + " attempted.");
msg.AppendLine("Successfully deleted " + deleted.ToString() + " features of " + totalDeletes.ToString() + " attempted.");
EditStatusTextBlock.Text = msg.ToString();


For descriptions of errors that can arise during edit commits, go to the Apply Edits (Feature Service) topic and click the error code link in the Description section.


In a disconnected workflow, commit all edits back to the service, and optionally pull the latest changes from the service back to your geodatabase through a sync operation, as described in Sync offline edits. Syncing requires a network connection; therefore, do this when you are back online. Note that the edits that are last committed to the service will overwrite previously committed edits, even if committed edits were made at a later time.

Related topics