-
Notifications
You must be signed in to change notification settings - Fork 120
ProSnippets Editing
Language: C#
Subject: Editing
Contributor: ArcGIS Pro SDK Team <[email protected]>
Organization: Esri, http://www.esri.com
Date: 11/7/2025
ArcGIS Pro: 3.6
Visual Studio: 2022
// Checks for pending actions in an edit operation before attempting to execute it.
await QueuedTask.Run(() =>
{
// Create an edit operation
var op = new EditOperation() { Name = "My Edit Operation" };
// Add some actions to the edit operation
op.Modify(featureLayer, objectId, geometry);
// EditOperation.Modify can unknowingly set an attribute to the already existing value
// In this scenario the Modify action will detect that no changes are required and consequently the Execute operation will fail.
// To avoid this, we can check if the edit operation is empty before executing it.
if (!op.IsEmpty)
{
// Execute the edit operation
var result = op.Execute();
Debug.WriteLine($"Edit operation executed successfully: {result}");
}
else
{
Debug.WriteLine("No actions to execute in the edit operation.");
}
});// Creates new features in a feature layer using the specified geometry, attributes, or editing template.
await QueuedTask.Run(() =>
{
var createFeatures = new EditOperation() { Name = "Create Features" };
//Create a feature with a polygon
var token = createFeatures.Create(featureLayer, polygon);
if (createFeatures.IsSucceeded)
{
// token.ObjectID will be populated with the objectID of the created feature after Execute has been successful
}
//Do a create features and set attributes
var attributes = new Dictionary<string, object>
{
{ "SHAPE", polygon },
{ "NAME", "Corner Market" },
{ "SIZE", 1200.5 },
{ "DESCRIPTION", "Corner Market" }
};
createFeatures.Create(featureLayer, attributes);
//Create features using the current template
//Must be within a MapTool
createFeatures.Create(currentTemplate, polygon);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!createFeatures.IsEmpty)
{
//Execute will return true if the operation was successful and false if not.
createFeatures.Execute();
//or use async flavor
//await createFeatures.ExecuteAsync();
}
});// Creates a new feature using the current editing template and the specified geometry.
await QueuedTask.Run(() =>
{
var myTemplate = currentTemplate ?? ArcGIS.Desktop.Editing.Templates.EditingTemplate.Current;
//Create edit operation and execute
var op = new ArcGIS.Desktop.Editing.EditOperation() { Name = "Create my feature" };
op.Create(myTemplate, geometry);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Creates a new feature by copying and optionally modifying the attributes of an existing feature using an inspector.
await QueuedTask.Run(() =>
{
// Create an inspector and load a feature
// The inspector is used to modify the attributes of the feature before creating it
var insp = new Inspector();
insp.Load(featureLayer, objectId);
// modify attributes if necessary
// insp["Field1"] = newValue;
//Create new feature from an existing inspector (copying the feature)
var createOp = new EditOperation() { Name = "Create from insp" };
createOp.Create(insp.MapMember, insp.ToDictionary(a => a.FieldName, a => a.CurrentValue));
if (!createOp.IsEmpty)
{
var result = createOp.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Creates new point features in the specified feature layer using data from a CSV source.
var csvData = new List<(double X, double Y, double StopOrder, double FacilityID)>();
//Run on MCT
await QueuedTask.Run(() =>
{
//Create the edit operation
var createOperation = new ArcGIS.Desktop.Editing.EditOperation() { Name = "Generate points", SelectNewFeatures = false };
// determine the shape field name - it may not be 'Shape'
string shapeField = featureLayer.GetFeatureClass().GetDefinition().GetShapeField();
//Loop through csv data
foreach (var item in csvData)
{
//Create the point geometry
ArcGIS.Core.Geometry.MapPoint newMapPoint =
ArcGIS.Core.Geometry.MapPointBuilderEx.CreateMapPoint(item.X, item.Y);
// include the attributes via a dictionary
var atts = new Dictionary<string, object>
{
{ "StopOrder", item.StopOrder },
{ "FacilityID", item.FacilityID },
{ shapeField, newMapPoint }
};
// queue feature creation
createOperation.Create(featureLayer, atts);
}
// execute the edit (feature creation) operation
if (createOperation.IsEmpty)
{
return createOperation.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
else
return false;
});// Creates a new row in a standalone table using the specified table template.
await QueuedTask.Run(() =>
{
var tableTemplate = standaloneTable.GetTemplates().FirstOrDefault();
var createRow = new EditOperation() { Name = "Create a row in a table" };
//Creating a new row in a standalone table using the table template of your choice
createRow.Create(tableTemplate);
if (!createRow.IsEmpty)
{
var result = createRow.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Clips a feature to the specified polygon.
await QueuedTask.Run(() =>
{
var clipFeatures = new EditOperation() { Name = "Clip Features" };
clipFeatures.Clip(featureLayer, objectId, clipPolygon, ClipMode.PreserveArea);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!clipFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = clipFeatures.Execute();
//or use async flavor
//await clipFeatures.ExecuteAsync();
}
});// Cuts features in the specified feature layer using the provided cut line and clip polygon.
await QueuedTask.Run(() =>
{
var select = MapView.Active.SelectFeatures(clipPolygon);
var cutFeatures = new EditOperation() { Name = "Cut Features" };
cutFeatures.Split(featureLayer, objectId, cutLine);
//Cut all the selected features in the active view
//Select using a polygon (for example)
cutFeatures.Split(select, cutLine);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!cutFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = cutFeatures.Execute();
//or use async flavor
//await cutFeatures.ExecuteAsync();
}
});// Deletes a single feature from the specified feature layer using its ObjectID.
await QueuedTask.Run(() =>
{
var deleteFeatures = new EditOperation() { Name = "Delete single feature" };
//Delete a row in a standalone table
deleteFeatures.Delete(featureLayer, objectId);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!deleteFeatures.IsEmpty)
{ //Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = deleteFeatures.Execute();
//or use async flavor
//await deleteFeatures.ExecuteAsync();
}
});// Duplicates a feature in a feature layer and modifies its geometry.
await QueuedTask.Run(() =>
{
var duplicateFeatures = new EditOperation() { Name = "Duplicate Features" };
//Duplicate with an X and Y offset of 500 map units
//Execute to execute the operation
//Must be called within QueuedTask.Run
var insp2 = new Inspector();
insp2.Load(featureLayer, objectId);
var geom = insp2["SHAPE"] as Geometry;
var rtoken = duplicateFeatures.Create(insp2.MapMember, insp2.ToDictionary(a => a.FieldName, a => a.CurrentValue));
if (!duplicateFeatures.IsEmpty)
{
if (duplicateFeatures.Execute())//Execute and ExecuteAsync will return true if the operation was successful and false if not
{
var modifyOp = duplicateFeatures.CreateChainedOperation();
modifyOp.Modify(featureLayer, (long)rtoken.ObjectID, GeometryEngine.Instance.Move(geom, 500.0, 500.0));
if (!modifyOp.IsEmpty)
{
var result = modifyOp.Execute();
}
}
}
});// Explodes a multi-part feature into individual features.
await QueuedTask.Run(() =>
{
var explodeFeatures = new EditOperation() { Name = "Explode Features" };
//Take a multipart and convert it into one feature per part
//Provide a list of ids to convert multiple
explodeFeatures.Explode(featureLayer, [objectId], true);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!explodeFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = explodeFeatures.Execute();
//or use async flavor
//await explodeFeatures.ExecuteAsync();
}
});// Merges multiple features from a source feature layer into a new feature, optionally using a template or inspector, and supports merging into a destination layer.
await QueuedTask.Run(() =>
{
var mergeFeatures = new EditOperation() { Name = "Merge Features" };
//Merge three features into a new feature using defaults
//defined in the current template
mergeFeatures.Merge(currentTemplate as EditingRowTemplate, featureLayer, [10, 96, 12]);
//Merge three features into a new feature in the destination layer
mergeFeatures.Merge(destinationLayer, featureLayer, [10, 96, 12]);
//Use an inspector to set the new attributes of the merged feature
var inspector = new Inspector();
inspector.Load(featureLayer, objectId);//base attributes on an existing feature
inspector["NAME"] = "New name";
inspector["DESCRIPTION"] = "New description";
//Merge features into a new feature in the same layer using the
//defaults set in the inspector
mergeFeatures.Merge(featureLayer, [10, 96, 12], inspector);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!mergeFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = mergeFeatures.Execute();
//or use async flavor
//await mergeFeatures.ExecuteAsync();
}
});// Modifies a single feature in the specified feature layer.
await QueuedTask.Run(() =>
{
var modifyFeature = new EditOperation() { Name = "Modify a feature" };
//use an inspector
var modifyInspector = new Inspector();
modifyInspector.Load(featureLayer, objectId);//base attributes on an existing feature
//change attributes for the new feature
modifyInspector["SHAPE"] = polygon;//Update the geometry
modifyInspector["NAME"] = "Updated name";//Update attribute(s)
modifyFeature.Modify(modifyInspector);
//update geometry and attributes using overload
var featureAttributes = new Dictionary<string, object>
{
["NAME"] = "Updated name"//Update attribute(s)
};
modifyFeature.Modify(featureLayer, objectId, polygon, featureAttributes);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!modifyFeature.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = modifyFeature.Execute();
//or use async flavor
//await modifyFeatures.ExecuteAsync();
}
});// Modifies multiple features in the specified feature layer by updating their attributes.
await QueuedTask.Run(() =>
{
//Search by attribute
var queryFilter = new QueryFilter() { WhereClause = "OBJECTID < 1000000" };
//Create list of oids to update
var oidSet = new List<long>();
using (var rc = featureLayer.Search(queryFilter))
{
while (rc.MoveNext())
{
using var record = rc.Current;
oidSet.Add(record.GetObjectID());
}
}
//create and execute the edit operation
var modifyFeatures = new EditOperation
{
Name = "Modify features",
ShowProgressor = true
};
var multipleFeaturesInsp = new Inspector();
multipleFeaturesInsp.Load(featureLayer, oidSet);
multipleFeaturesInsp["MOMC"] = 24;
modifyFeatures.Modify(multipleFeaturesInsp);
if (!modifyFeatures.IsEmpty)
{
var result = modifyFeatures.ExecuteAsync(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});var oidSet = new List<long>();
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
//find layer
var disLayer = ArcGIS.Desktop.Mapping.MapView.Active.Map.FindLayers("Distribution mains").FirstOrDefault() as BasicFeatureLayer;
//Search by attribute
var filter = new ArcGIS.Core.Data.QueryFilter { WhereClause = "CONTRACTOR = 'KCGM'" };
var oids = new List<long>();
using (var rc = disLayer.Search(filter))
{
//Create list of oids to update
while (rc.MoveNext())
{
using (var record = rc.Current)
{
oidSet.Add(record.GetObjectID());
}
}
}
//Create edit operation
var modifyOp = new EditOperation() { Name = "Update date" };
// load features into inspector and update field
var dateInsp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
dateInsp.Load(disLayer, oids);
dateInsp["InspDate"] = "9/21/2013";
// modify and execute
modifyOp.Modify(insp);
if (!modifyOp.IsEmpty)
{
var result = modifyOp.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}// Moves the shapes (geometries) of all selected features of a given feature layer of the active map view by a fixed offset.
await QueuedTask.Run<bool>(() =>
{
double xOffset = 100; // specify your units along the x-axis to move the geometry
double yOffset = 100; // specify your units along the y-axis to move the geometry
// If there are no selected features, return
if (featureLayer.GetSelection().GetObjectIDs().Count == 0)
return false;
// set up a dictionary to store the layer and the object IDs of the selected features
var selectionDictionary = new Dictionary<MapMember, List<long>>
{
{ featureLayer, featureLayer.GetSelection().GetObjectIDs().ToList() }
};
var moveEditOperation = new EditOperation() { Name = "Move features" };
moveEditOperation.Move(SelectionSet.FromDictionary(selectionDictionary), xOffset, yOffset); //specify your units along axis to move the geometry
if (!moveEditOperation.IsEmpty)
{
var result = moveEditOperation.Execute();
return result; // return the operation result: true if successful, false if not
}
return false; // return false to indicate that the operation was not empty
});// Moves the first selected feature in the specified feature layer to the given coordinates.
await QueuedTask.Run<bool>(() =>
{
//Get all of the selected ObjectIDs from the layer.
var mySelection = featureLayer.GetSelection();
var selOid = mySelection.GetObjectIDs()?[0];
var xCoordinate = 0.0;
var yCoordinate = 0.0; // specify the target coordinates to move the geometry
var moveToPoint = new MapPointBuilderEx(xCoordinate, yCoordinate, 0.0, 0.0, featureLayer.GetSpatialReference());
var moveEditOperation = new EditOperation() { Name = "Move features" };
moveEditOperation.Modify(featureLayer, selOid ?? -1, moveToPoint.ToGeometry()); //Modify the feature to the new geometry
if (!moveEditOperation.IsEmpty)
{
var result = moveEditOperation.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
return result; // return the operation result: true if successful, false if not
}
return false; // return false to indicate that the operation was not empty
});// Planarizes the specified feature in the given feature layer.
await QueuedTask.Run(() =>
{
// note - EditOperation.Planarize requires a standard license.
// An exception will be thrown if Pro is running under a basic license.
var planarizeFeatures = new EditOperation() { Name = "Planarize Features" };
// Planarize one or more features
planarizeFeatures.Planarize(featureLayer, [objectId]);
// Execute to execute the operation
// Must be called within QueuedTask.Run
if (!planarizeFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = planarizeFeatures.Execute();
//or use async flavor
//await planarizeFeatures.ExecuteAsync();
}
});// Creates parallel offset features from the selected features.
await QueuedTask.Run(static () =>
{
//Create parallel features from the selected features
//find the roads layer
var roadsLayer = MapView.Active.Map.FindLayers("Roads")?[0];
//instantiate parallelOffset builder and set parameters
var parOffsetBuilder = new ParallelOffset.Builder()
{
Selection = MapView.Active.Map.GetSelection(),
Template = roadsLayer.GetTemplate("Freeway"),
Distance = 200,
Side = ParallelOffset.SideType.Both,
Corner = ParallelOffset.CornerType.Mitered,
Iterations = 1,
AlignConnected = false,
CopyToSeparateFeatures = false,
RemoveSelfIntersectingLoops = true
};
//create EditOperation and execute
var parallelOp = new EditOperation();
parallelOp.Create(parOffsetBuilder);
if (!parallelOp.IsEmpty)
{
var result = parallelOp.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Reshapes the specified feature in the given feature layer.
await QueuedTask.Run(() =>
{
var reshapeFeatures = new EditOperation() { Name = "Reshape Features" };
reshapeFeatures.Reshape(featureLayer, objectId, modifyLine);
//Reshape a set of features that intersect some geometry....
reshapeFeatures.Reshape(MapView.Active.GetFeatures(modifyLine), modifyLine);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!reshapeFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = reshapeFeatures.Execute();
//or use async flavor
//await reshapeFeatures.ExecuteAsync();
}
});// Rotates the selected features by a specified angle.
await QueuedTask.Run(() =>
{
var rotateFeatures = new EditOperation() { Name = "Rotate Features" };
//Rotate works on a selected set of features
//Get all features that intersect a polygon
//Rotate selected features 90 deg about "origin"
rotateFeatures.Rotate(MapView.Active.GetFeatures(polygon), origin, angle);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!rotateFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = rotateFeatures.Execute();
//or use async flavor
//await rotateFeatures.ExecuteAsync();
}
});// Scales the selected features by a specified factor.
await QueuedTask.Run(() =>
{
var scaleFeatures = new EditOperation() { Name = "Scale Features" };
var scale = 2.0; // specify the scale factor for x and y
//Rotate works on a selected set of features
//Scale the selected features by scale in the X and Y direction
scaleFeatures.Scale(MapView.Active.GetFeatures(polygon), origin, scale, scale, 0.0);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!scaleFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = scaleFeatures.Execute();
//or use async flavor
//await scaleFeatures.ExecuteAsync();
}
});// Splits the specified feature at the given points.
await QueuedTask.Run(() =>
{
//Split features at given points
//Split features using EditOperation.Split overloads
var splitFeatures = new EditOperation() { Name = "Split Features" };
//Split the feature at given points
splitFeatures.Split(featureLayer, objectId, splitPoints);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!splitFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = splitFeatures.Execute();
//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();
}
});
// Splits a feature in the specified feature layer based on a given percentage and object ID.
await QueuedTask.Run(() =>
{
var percentage = 25.0;
//Split features using EditOperation.Split overloads
var splitFeatures = new EditOperation() { Name = "Split Features" };
// split using percentage
var splitByPercentage = new SplitByPercentage() { Percentage = percentage, SplitFromStartPoint = true };
splitFeatures.Split(featureLayer, objectId, splitByPercentage);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!splitFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = splitFeatures.Execute();
//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();
}
});
// Splits a feature in the specified feature layer into the specified number of parts.
await QueuedTask.Run(() =>
{
var numParts = 3;
// split using equal parts
//Split features using EditOperation.Split overloads
var splitFeatures = new EditOperation() { Name = "Split Features" };
var splitByEqualParts = new SplitByEqualParts() { NumParts = numParts };
splitFeatures.Split(featureLayer, objectId, splitByEqualParts);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!splitFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = splitFeatures.Execute();
//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();
}
});
// Splits a feature in the specified feature layer at a given distance and object ID.
await QueuedTask.Run(() =>
{
var distance = 150.0;
//Split features using EditOperation.Split overloads
var splitFeatures = new EditOperation() { Name = "Split Features" };
// split using single distance
var splitByDistance = new SplitByDistance() { Distance = distance, SplitFromStartPoint = false };
splitFeatures.Split(featureLayer, objectId, splitByDistance);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!splitFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = splitFeatures.Execute();
//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();
}
});
// Splits a feature in the specified feature layer at a given distance and object ID.
await QueuedTask.Run(() =>
{
var distances = new List<double> { 100.0, 200.0, 50.0 };
//Split features using EditOperation.Split overloads
var splitFeatures = new EditOperation() { Name = "Split Features" };
// split using varying distance
var splitByVaryingDistance = new SplitByVaryingDistance() { Distances = distances, SplitFromStartPoint = true, ProportionRemainder = true };
splitFeatures.Split(featureLayer, objectId, splitByVaryingDistance);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!splitFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = splitFeatures.Execute();
//or use async flavor
//await splitAtPointsFeatures.ExecuteAsync();
}
});// Transfers attributes from a source feature to a target feature between specified layers.
await QueuedTask.Run(() =>
{
var targetOID = 12345; // object ID of the target feature in the destination layer
var transferAttributes = new EditOperation() { Name = "Transfer Attributes" };
// transfer attributes using the stored field mapping
transferAttributes.TransferAttributes(featureLayer, objectId, destinationLayer, targetOID);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!transferAttributes.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = transferAttributes.Execute();
//or use async flavor
//await transferAttributes.ExecuteAsync();
}
});
// Transfers attributes from a source feature to a target feature between specified layers.
await QueuedTask.Run(() =>
{
var targetOID = 12345; // object ID of the target feature in the destination layer
var transferAttributes = new EditOperation() { Name = "Transfer Attributes" };
// transfer attributes using an auto-match on the attributes
transferAttributes.TransferAttributes(featureLayer, objectId, destinationLayer, targetOID, "");
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!transferAttributes.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = transferAttributes.Execute();
//or use async flavor
//await transferAttributes.ExecuteAsync();
}
});
// Transfers attributes from a source feature to a target feature in a specified destination layer.
await QueuedTask.Run(() =>
{
var targetOID = 12345; // object ID of the target feature in the destination layer
var transferAttributes = new EditOperation() { Name = "Transfer Attributes" };
// transfer attributes using a specified set of field mappings
// dictionary key is the field name in the destination layer, dictionary value is the field name in the source layer
Dictionary<string, string> fldMapping = new() {
{ "NAME", "SURNAME" },
{ "ADDRESS", "ADDRESS" }
};
transferAttributes.TransferAttributes(featureLayer, objectId, destinationLayer, targetOID, fldMapping);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!transferAttributes.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = transferAttributes.Execute();
//or use async flavor
//await transferAttributes.ExecuteAsync();
}
});
// Transfers attributes from a source feature to a target feature in a specified destination layer.
await QueuedTask.Run(() =>
{
var targetOID = 12345; // object ID of the target feature in the destination layer
var transferAttributes = new EditOperation() { Name = "Transfer Attributes" };
// transfer attributes using a custom field mapping expression
string expression = "return {\r\n " +
"\"ADDRESS\" : $sourceFeature['ADDRESS'],\r\n " +
"\"IMAGE\" : $sourceFeature['IMAGE'],\r\n + " +
"\"PRECINCT\" : $sourceFeature['PRECINCT'],\r\n " +
"\"WEBSITE\" : $sourceFeature['WEBSITE'],\r\n " +
"\"ZIP\" : $sourceFeature['ZIP']\r\n " +
"}";
transferAttributes.TransferAttributes(featureLayer, objectId, destinationLayer, targetOID, expression);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!transferAttributes.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = transferAttributes.Execute();
//or use async flavor
//await transferAttributes.ExecuteAsync();
}
});// Transforms features from a source layer to a target layer using a specified transformation method.
await QueuedTask.Run(() =>
{
//Transform features using EditOperation.Transform overloads
var transformFeatures = new EditOperation() { Name = "Transform Features" };
//Transform a selected set of features
////Perform an affine transformation
//transformFeatures.TransformAffine(featureLayer, linkLayer);
var affine_transform = new TransformByLinkLayer()
{
LinkLayer = linkLayer,
TransformType = TransformMethodType.Affine //TransformMethodType.Similarity
};
//Transform a selected set of features
transformFeatures.Transform(MapView.Active.GetFeatures(polygon), affine_transform);
//Perform an affine transformation
transformFeatures.Transform(featureLayer, affine_transform);
//Execute to execute the operation
//Must be called within QueuedTask.Run
if (!transformFeatures.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = transformFeatures.Execute();
//or use async flavor
//await transformFeatures.ExecuteAsync();
}
});// Performs a rubber-sheet transformation on the features of a specified layer using the provided link lines, anchor points, and limited adjustment areas.
await QueuedTask.Run(() =>
{
//Perform rubber-sheet by geometries
var rubbersheetMethod = new RubbersheetByGeometries()
{
RubbersheetType = RubbersheetMethodType.Linear, //The RubbersheetType can be Linear of NearestNeighbor
LinkLines = linkLines, //IEnumerable list of link lines (polylines)
AnchorPoints = anchorPoints, //IEnumerable list of anchor points (map points)
LimitedAdjustmentAreas = limitedAdjustmentAreas //IEnumerable list of limited adjustment areas (polygons)
};
var rubbersheetOp = new EditOperation();
//Performs linear rubber-sheet transformation on the features belonging to "layer" that fall within the limited adjustment areas
rubbersheetOp.Rubbersheet(layer, rubbersheetMethod);
//Execute the operation
if (!rubbersheetOp.IsEmpty)
{
var result = rubbersheetOp.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
//Alternatively, you can also perform rubber-sheet by layer
var rubbersheetMethod2 = new RubbersheetByLayers()
{
RubbersheetType = RubbersheetMethodType.NearestNeighbor, //The RubbersheetType can be Linear of NearestNeighbor
LinkLayer = linkLayer,
AnchorPointLayer = anchorPointsLayer,
LimitedAdjustmentAreaLayer = limitedAdjustmentAreaLayer
};
//Performs nearest neighbor rubber-sheet transformation on the features belonging to "layer" that fall within the limited adjustment areas
rubbersheetOp.Rubbersheet(layer, rubbersheetMethod2);
if (!rubbersheetOp.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = rubbersheetOp.Execute();
}
});// Performs a sequence of editing operations on a feature, including clipping, cutting, and planarizing.
await QueuedTask.Run(() =>
{
//Multiple operations can be performed by a single
//edit operation.
var clipCutPlanarizeFeatures = new EditOperation() { Name = "Clip, Cut, and Planarize Features" };
clipCutPlanarizeFeatures.Clip(featureLayer, objectId, clipPolygon);
clipCutPlanarizeFeatures.Split(featureLayer, objectId, cutLine);
clipCutPlanarizeFeatures.Planarize(featureLayer, objectId);
if (!clipCutPlanarizeFeatures.IsEmpty)
{
//Note: An edit operation is a single transaction.
//Execute the operations (in the order they were declared)
//Execute and ExecuteAsync will return true if the operation was successful and false if not
clipCutPlanarizeFeatures.Execute();
//or use async flavor
//await clipCutPlanarizeFeatures.ExecuteAsync();
}
});// Chains multiple edit operations into a single undo-able transaction.
await QueuedTask.Run(() =>
{
//Chaining operations is a special case. Use "Chained Operations" when you require multiple transactions
//to be undo-able with a single "Undo".
//The most common use case for operation chaining is creating a feature with an attachment.
//Adding an attachment requires the object id (of a new feature) has already been created.
var editOperation1 = new EditOperation() { Name = string.Format("Create point in '{0}'", currentTemplate.Layer.Name) };
long newFeatureID = -1;
//The Create operation has to execute so we can get an object_id
var token2 = editOperation1.Create(currentTemplate, polygon);
//Must be within a QueuedTask
editOperation1.Execute(); //Note: Execute and ExecuteAsync will return true if the operation was successful and false if not
if (editOperation1.IsSucceeded)
{
newFeatureID = (long)token2.ObjectID;
//Now, because we have the object id, we can add the attachment. As we are chaining it, adding the attachment
//can be undone as part of the "Undo Create" operation. In other words, only one undo operation will show on the
//Pro UI and not two.
var editOperation2 = editOperation1.CreateChainedOperation();
//Add the attachment using the new feature id
editOperation2.AddAttachment(currentTemplate.Layer, newFeatureID, @"C:\data\images\Hydrant.jpg");
//Execute the chained edit operation. editOperation1 and editOperation2 show up as a single Undo operation
//on the UI even though we had two transactions
editOperation2.Execute();
}
});// Creates a new feature using the specified editing template and polygon geometry, and adds an attachment to the feature in a single edit operation.
await QueuedTask.Run(() =>
{
//The EditOperation.AddAttachment method to take a RowToken as a parameter
//allows you to create a feature, using EditOperation.CreateEx, and add an attachment in one transaction.
EditOperation editOpAttach = new()
{
Name = string.Format($@"Create new polygon with attachment in '{currentTemplate.Layer.Name}'")
};
var attachRowToken = editOpAttach.Create(currentTemplate, polygon);
editOpAttach.AddAttachment(attachRowToken, @"c:\temp\image.jpg");
//Must be within a QueuedTask
if (!editOpAttach.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = editOpAttach.Execute();
}
});// Modifies the "NAME" attribute of a specified feature and then splits the feature using the provided polyline, all within a single sequential edit operation.
// perform an edit and then a split as one operation.
await QueuedTask.Run(() =>
{
var newName = "Modified then Split";
var queryFilter = new QueryFilter() { WhereClause = "OBJECTID = " + objectId.ToString() };
// create an edit operation and name.
var op = new EditOperation
{
Name = "modify followed by split", // set the ExecuteMode
ExecuteMode = ExecuteModeType.Sequential
};
using (var rowCursor = layer.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
using var feature = rowCursor.Current as ArcGIS.Core.Data.Feature;
op.Modify(feature, "NAME", newName);
}
}
op.Split(layer, objectId, splitLine);
if (!op.IsEmpty)
{
bool result = op.Execute();
}
// else
// The operation doesn't make any changes to the database so if executed it will fail
});// Demonstrates how to use the <see cref="ArcGIS.Desktop.Editing.EditOperation"/> methods <see
await QueuedTask.Run(() =>
{
// SetOnUndone, SetOnRedone and SetOnComitted can be used to manage
// external actions(such as writing to a log table) that are associated with
// each edit operation.
//get selected feature and update attribute
var selectedFeatures = MapView.Active.Map.GetSelection();
var testInspector = new Inspector();
testInspector.Load(selectedFeatures.ToDictionary().Keys.First(), selectedFeatures.ToDictionary().Values.First());
testInspector["Name"] = "test";
//create and execute the edit operation
var updateTestField = new EditOperation() { Name = "Update test field" };
updateTestField.Modify(testInspector);
//actions for SetOn...
updateTestField.SetOnUndone(() =>
{
//Sets an action that will be called when this operation is undone.
Debug.WriteLine("Operation is undone");
});
updateTestField.SetOnRedone(() =>
{
//Sets an action that will be called when this edit operation is redone.
Debug.WriteLine("Operation is redone");
});
updateTestField.SetOnComitted(b =>
{
// Sets an action that will be called when this edit operation is committed.
Debug.WriteLine("Operation is committed");
});
if (!updateTestField.IsEmpty)
{
var result = updateTestField.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});//Control points are special vertices used to apply symbol effects to line or polygon features.
//By default, they appear as diamonds when you edit them.
//They can also be used to migrate representations from ArcMap to features in ArcGIS Pro.
await QueuedTask.Run(() =>
{
var changeVertexIDOperation = new EditOperation();
//iterate through the points in the polyline.
var lineLayerCursor = lineLayer.GetSelection().Search();
var lineVertices = new List<MapPoint>();
long objectId = -1;
while (lineLayerCursor.MoveNext())
{
var lineFeature = lineLayerCursor.Current as ArcGIS.Core.Data.Feature;
var line = lineFeature.GetShape() as Polyline;
int vertexIndex = 1;
objectId = lineFeature.GetObjectID();
//Each point is converted into a MapPoint and gets added to a list.
foreach (var point in line.Points)
{
MapPointBuilderEx mapPointBuilderEx = new(point);
//Changing the vertex 6 and 7 to control points
if (vertexIndex == 6 || vertexIndex == 7)
{
//These points are made "ID Aware" and the IDs are set to be 1.
mapPointBuilderEx.HasID = true;
mapPointBuilderEx.ID = 1;
}
lineVertices.Add(mapPointBuilderEx.ToGeometry() as MapPoint);
vertexIndex++;
}
}
//create a new polyline using the point collection.
var newLine = PolylineBuilderEx.CreatePolyline(lineVertices);
//edit operation to modify the original line with the new line that contains control points.
changeVertexIDOperation.Modify(lineLayer, objectId, newLine);
changeVertexIDOperation.Execute();
});
}// Enables editing for the current project asynchronously.
if (!Project.Current.IsEditingEnabled)
{
var bEditingIsEnabled = await Project.Current.SetIsEditingEnabledAsync(true);
}// Disables editing for the current project.
// discard any edits if they exist
var discardEdits = true;
// only needed if editing is enabled
if (Project.Current.IsEditingEnabled)
{
// check for edits
if (Project.Current.HasEdits)
{
if (discardEdits)
await Project.Current.DiscardEditsAsync();
else
await Project.Current.SaveEditsAsync();
}
var bEditingIsEnabled = !Project.Current.SetIsEditingEnabledAsync(false).Result;
}// ApplicationOptions.EditingOptions.EnableEditingFromEditTab is true
// ApplicationOptions.EditingOptions.IsSingleWorkspaceEditSession is true
// find a layer
var mm = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "Roads");
if (mm == null)
return;
var project = Project.Current;
var success = await project.SetSingleEditWorkspaceAsync(mm);
// if success = true then an edit session was started
// and project.IsEditingEnabled will be true// ApplicationOptions.EditingOptions.EnableEditingFromEditTab is true
// ApplicationOptions.EditingOptions.IsSingleWorkspaceEditSession is true
var project = Project.Current;
// check if already editing
if (project.IsEditingEnabled)
{
// save or discard any edits
if (project.HasEdits)
{
var res = MessageBox.Show("Save edits?", "Save Edits?", System.Windows.MessageBoxButton.YesNoCancel);
if (res == System.Windows.MessageBoxResult.Cancel)
return;
else if (res == System.Windows.MessageBoxResult.No)
await project.DiscardEditsAsync();
else
await project.SaveEditsAsync();
}
// close the edit session
await project.SetIsEditingEnabledAsync(false);
}
// find a layer
var mm = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "Roads");
if (mm == null)
return;
// start the edit session on the workspace attached to the layer
var success = await project.SetSingleEditWorkspaceAsync(mm);
// if success = true then an edit session was started
// and project.IsEditingEnabled will be true// ApplicationOptions.EditingOptions.EnableEditingFromEditTab is true
// ApplicationOptions.EditingOptions.IsSingleWorkspaceEditSession is true
Geodatabase egdb = new Geodatabase(new DatabaseConnectionFile(new Uri("path\\to\\sde\\file\\sdefile.sde")));
// setup the configuration to edit the data registered as versioned in the egdb
var datastoreConfig = new DatastoreConfiguration(egdb, VersionState.Versioned);
// start the edit session on the workspace
var project = Project.Current;
var v_success = await project.SetSingleEditWorkspaceAsync(datastoreConfig);
// OR
// setup the configuration to edit the data that is not registered as versioned
var nonVersionedDatastoreConfig = new DatastoreConfiguration(egdb, VersionState.NonVersioned);
// start the edit session on the workspace
var nv_success = await project.SetSingleEditWorkspaceAsync(nonVersionedDatastoreConfig);// Subscribes to row events for the currently selected feature layer in the active map view.
await QueuedTask.Run(() =>
{
//Listen for row events on a layer
var featLayer = MapView.Active.GetSelectedLayers()[0] as FeatureLayer;
var layerTable = featLayer.GetTable();
//subscribe to row events
// row created event
var rowCreateToken = RowCreatedEvent.Subscribe(rowChangedEventArgs => { }, layerTable);
// row changed event
var rowChangeToken = RowChangedEvent.Subscribe(rowChangedEventArgs => { }, layerTable);
// row deleted event
var rowDeleteToken = RowDeletedEvent.Subscribe(rowChangedEventArgs => { }, layerTable);
});// attach an event handler to receive notifications when a new row is created in the
// associated table of the first feature layer found in the active map. Use this method to enable custom logic in
// response to row creation events within your ArcGIS Pro add-in.
// subscribe to the RowCreatedEvent
Table table = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowCreatedEvent.Subscribe(rowChangedEventArgs =>
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
// get the edit operation
var parentEditOp = rowChangedEventArgs.Operation;
// set up some attributes
var attribs = new Dictionary<string, object>
{
{ "Layer", "Parcels" },
{ "Description", "objectId: " + rowChangedEventArgs.Row.GetObjectID().ToString() + " " + DateTime.Now.ToShortTimeString() }
};
//create a record in an audit table
var sTable = MapView.Active.Map.FindStandaloneTables("EditHistory")[0];
var table = sTable.GetTable();
parentEditOp.Create(table, attribs);
}, table);// Attach an event handler to the <see cref="ArcGIS.Desktop.Editing.Events.RowCreatedEvent"/> for the table associated with the first <see cref="ArcGIS.Desktop.Mapping.FeatureLayer"/> in the active map. Use this method to monitor when new rows are created
// in that table, enabling custom logic to be executed in response to record creation events.
Table firstTable = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowCreatedEvent.Subscribe(rowChangedEventArgs =>
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
// update a separate table not in the map when a row is created
// You MUST use the ArcGIS.Core.Data API to edit the table. Do NOT
// use a new edit operation in the RowEvent callbacks
try
{
// get the edit operation
var parentEditOp = rowChangedEventArgs.Operation;
// set up some attributes
var attribs = new Dictionary<string, object>
{
{ "Description", "objectId: " + rowChangedEventArgs.Row.GetObjectID().ToString() + " " + DateTime.Now.ToShortTimeString() }
};
// update Notes table with information about the new feature
using var geoDatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(Project.Current.DefaultGeodatabasePath)));
using var table = geoDatabase.OpenDataset<Table>("Notes");
parentEditOp.Create(table, attribs);
}
catch (Exception e)
{
throw new Exception($@"Error in OnRowCreated for objectId: {rowChangedEventArgs.Row.GetObjectID()} : {e}");
}
}, firstTable);// Attach an event handler to receive notifications when a row in the selected
// table is changed. The subscription targets the first <see cref="ArcGIS.Desktop.Mapping.FeatureLayer"/> found in
// the active map. Use this method to monitor and respond to edits made to table records within the current map
// context.
Table thisTable = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowChangedEvent.Subscribe(rowChangedEventArgs =>
{
// set the current row changed guid when you execute the Row.Store method
// used for re-entry checking
Guid _currentRowChangedGuid = new();
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
var row = rowChangedEventArgs.Row;
// check for re-entry (only if row.Store is called)
if (_currentRowChangedGuid == rowChangedEventArgs.Guid)
return;
var fldIdx = row.FindField("POLICE_DISTRICT");
if (fldIdx != -1)
{
//Validate any change to �police district�
// cancel the edit if validation on the field fails
if (row.HasValueChanged(fldIdx))
{
// cancel edit with invalid district (5)
var value = row["POLICE_DISTRICT"].ToString();
if (value == "5")
{
//Cancel edits with invalid �police district� values
rowChangedEventArgs.CancelEdit($"Police district {row["POLICE_DISTRICT"]} is invalid");
}
}
// update the description field
row["Description"] = "Row Changed";
// this update with cause another OnRowChanged event to occur
// keep track of the row guid to avoid recursion
_currentRowChangedGuid = rowChangedEventArgs.Guid;
row.Store();
_currentRowChangedGuid = Guid.Empty;
}
}, thisTable);// Subscribe to the <see cref="ArcGIS.Desktop.Editing.Events.RowChangedEvent"/> for
// the first <see cref="ArcGIS.Desktop.Mapping.FeatureLayer"/> in the active map. The event handler can be used to
// respond to changes in rows within the table, such as modifications or updates.
Table changeTable = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowChangedEvent.Subscribe(rowChangedEventArgs =>
{
// set the last row changed guid when you execute the Row.Store method
// used for re-entry checking
Guid _lastEdit = new();
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
//example of modifying a field on a row that has been created
var parentEditOp = rowChangedEventArgs.Operation;
// avoid recursion
if (_lastEdit != rowChangedEventArgs.Guid)
{
//update field on change
parentEditOp.Modify(rowChangedEventArgs.Row, "ZONING", "New");
_lastEdit = rowChangedEventArgs.Guid;
}
}, changeTable);// Set up a listener for row change events on the table associated with the
// provided feature layer. The event subscription occurs within a queued task to ensure thread safety.
await QueuedTask.Run(() =>
{
//Listen to the RowChangedEvent that occurs when a Row is changed.
var modifiedFeatureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(); ;
RowChangedEvent.Subscribe(rowChangedEventArgs =>
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
//Get the layer's definition
var lyrDefn = modifiedFeatureLayer.GetFeatureClass().GetDefinition();
//Get the shape field of the feature class
string shapeField = lyrDefn.GetShapeField();
//Index of the shape field
var shapeIndex = lyrDefn.FindField(shapeField);
//Original geometry of the modified row
var geomOrig = rowChangedEventArgs.Row.GetOriginalValue(shapeIndex) as Geometry;
//New geometry of the modified row
var geomNew = rowChangedEventArgs.Row[shapeIndex] as Geometry;
//Compare the two
bool shapeChanged = geomOrig.IsEqual(geomNew);
if (shapeChanged)
{
// The geometry has not changed
Console.WriteLine("Geometry has not changed");
}
else
{
// The geometry has changed
Console.WriteLine("Geometry has changed");
}
}, modifiedFeatureLayer.GetTable());
});// Subscribe to the <see cref="ArcGIS.Desktop.Editing.Events.RowDeletedEvent"/> for the first feature layer's table in the active map. The event handler can be used to intercept and handle row deletion events, such as canceling a delete operation if certain conditions are met.
// subscribe to the RowDeletedEvent for the appropriate table
// in preparation for the event: public static Guid _currentRowDeletedGuid = Guid.Empty;
Table cancelDeleteTable = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault().GetTable();
RowDeletedEvent.Subscribe(rowChangedEventArgs =>
{
// RowEvent callbacks are always called on the QueuedTask so there is no need
// to wrap your code within a QueuedTask.Run lambda.
var row = rowChangedEventArgs.Row;
// check for re-entry
if (_currentRowDeletedGuid == rowChangedEventArgs.Guid)
return;
// cancel the delete if the feature is in Police District 5
var fldIdx = row.FindField("POLICE_DISTRICT");
if (fldIdx != -1)
{
var value = row[fldIdx].ToString();
if (value == "5")
{
//cancel with dialog
// Note - feature edits on Hosted and Standard Feature Services cannot be cancelled.
rowChangedEventArgs.CancelEdit("Delete Event\nAre you sure", true);
// or cancel without a dialog
// args.CancelEdit();
}
}
_currentRowDeletedGuid = rowChangedEventArgs.Guid;
}, cancelDeleteTable);// Subscribe to the <see cref="ArcGIS.Desktop.Editing.Events.EditCompletedEvent"/>,
// allowing the application to respond to edit operations such as feature creation, modification, or deletion.public static void SubEditEvents()
var eceToken = EditCompletedEvent.Subscribe(editCompletedEventArgs =>
{
//show number of edits
Console.WriteLine("Creates: " + editCompletedEventArgs.Creates.ToDictionary().Values.Sum(list => list.Count).ToString());
Console.WriteLine("Modifies: " + editCompletedEventArgs.Modifies.ToDictionary().Values.Sum(list => list.Count).ToString());
Console.WriteLine("Deletes: " + editCompletedEventArgs.Deletes.ToDictionary().Values.Sum(list => list.Count).ToString());
return Task.FromResult(0);
});// Loads a feature from the specified feature layer into an Inspector instance.
// create an instance of the inspector class
var inspector = new Inspector();
// load the feature with ObjectID 'objectId' into the inspector
await inspector.LoadAsync(featureLayer, objectId);// Loads the selected features into an Inspector instance.
// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();
// create an instance of the inspector class
var inspector = new Inspector();
// load the selected features into the inspector using a list of object IDs
await inspector.LoadAsync(firstSelectionSet.Key, firstSelectionSet.Value);// Retrieves the value of a specific attribute and the geometry of the first selected feature from the provided selection set.
await QueuedTask.Run(() =>
{
// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();
// create an instance of the inspector class
var inspector = new Inspector();
// load the selected features into the inspector using a list of object IDs
inspector.Load(firstSelectionSet.Key, firstSelectionSet.Value);
//get the value of
var pscode = inspector["STATE_NAME"];
var myGeometry = inspector.Shape;
});// Updates the "Description" attribute of the selected features in the specified selection set.
{
// get the first layer and its corresponding selected feature OIDs
var firstSelectionSet = selectedFeatures.ToDictionary().First();
// create an instance of the inspector class
var inspector = new Inspector();
// load the selected features into the inspector using a list of object IDs
await inspector.LoadAsync(firstSelectionSet.Key, firstSelectionSet.Value);
// assign the new attribute value to the field "Description"
// if more than one features are loaded, the change applies to all features
inspector["Description"] = "The new value.";
// apply the changes as an edit operation
await inspector.ApplyAsync();
}// Loads the schema of the specified feature layer and iterates through its attributes, providing access to their properties such as field name, alias, type, and other metadata.
await QueuedTask.Run(() =>
{
// create an instance of the inspector class
var inspector = new Inspector();
// load the layer
inspector.LoadSchema(featureLayer);
// iterate through the attributes, looking at properties
foreach (var attribute in inspector)
{
var fldName = attribute.FieldName;
var fldAlias = attribute.FieldAlias;
var fldType = attribute.FieldType;
int idxFld = attribute.FieldIndex;
var fld = attribute.GetField();
var isNullable = attribute.IsNullable;
var isEditable = attribute.IsEditable;
var isVisible = attribute.IsVisible;
var isSystemField = attribute.IsSystemField;
var isGeometryField = attribute.IsGeometryField;
}
});// Adds a custom validation rule to the "Mineral" field of the specified feature layer.
await QueuedTask.Run(() =>
{
var insp = new Inspector();
insp.LoadSchema(featureLayer);
var attrib = insp.Where(a => a.FieldName == "Mineral").First();
attrib.AddValidate(() =>
{
if (attrib.CurrentValue.ToString() == "Salt")
return [];
else return [ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError.Create("Error", Severity.Low)];
});
});Provides a custom implementation of an InspectorProvider for feature inspection in ArcGIS Pro.
public class MyProvider : InspectorProvider
{
private Guid guid = Guid.NewGuid();
internal MyProvider() {}
public override Guid SharedFieldColumnSizeID() { return guid; }
public override string CustomName(ArcGIS.Desktop.Editing.Attributes.Attribute attr)
{
//Giving a custom name to be displayed for the field FeatureID
return attr.FieldName == "FeatureID" ? "Feature Identification" : attr.FieldName;
}
public override bool? IsVisible(Attribute attr)
{
//The field FontStyle will not be visible
return attr.FieldName == "FontStyle" ? false : true;
}
public override bool? IsEditable(Attribute attr)
{
//The field DateField will not be editable
return attr.FieldName == "DateField" ? false : true;
}
public override bool? IsHighlighted(Attribute attr)
{
//ZOrder field will be highlighted in the feature inspector grid
return attr.FieldName == "ZOrder" ? true : false;
}
public override IEnumerable<Attribute> AttributesOrder(IEnumerable<Attribute> attrs)
{
//Reverse the order of display
var newList = new List<Attribute>();
foreach (var attr in attrs)
{
newList.Insert(0, attr);
}
return newList;
}
public override bool? IsDirty(Attribute attr)
{
//The field will not be marked dirty for FeatureID if you enter the value -1
return attr.FieldName == "FeatureID" && attr.CurrentValue.ToString() == "-1" ? false : base.IsDirty(attr);
}
public override IEnumerable<ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError> Validate(Attribute attr)
{
var errors = new List<ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError>();
if (attr.FieldName == "FeatureID" && attr.CurrentValue.ToString() == "2")
errors.Add(ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError.Create("Value not allowed", Severity.Low));
if (attr.FieldName == "FeatureID" && attr.CurrentValue.ToString() == "-1")
errors.Add(ArcGIS.Desktop.Editing.Attributes.Attribute.ValidationError.Create("Invalid value", Severity.High));
return errors;
}
}Demonstrates the use of a custom InspectorProvider to create and load an inspector for a specific feature.
public static async void InspectorProviderExample(FeatureLayer featureLayer, long objectId)
{
var provider = new MyProvider();
Inspector _featureInspector = provider.Create();
//Create an embed-able control from the inspector class to display on the pane
var icontrol = _featureInspector.CreateEmbeddableControl();
await _featureInspector.LoadAsync(featureLayer, objectId);
var attribute = _featureInspector.Where(a => a.FieldName == "FontStyle").FirstOrDefault();
var visibility = attribute.IsVisible; //Will return false
attribute = _featureInspector.Where(a => a.FieldName == "ZOrder").FirstOrDefault();
var highlighted = attribute.IsHighlighted; //Will return true
}await QueuedTask.Run(() =>
{
// get selected feature into inspector
var selectedFeatures = activeMap.GetSelection();
var insp = new Inspector();
insp.Load(selectedFeatures.ToDictionary().Keys.First(), selectedFeatures.ToDictionary().Values.First());
// read a blob field and save to a file
var msw = new MemoryStream();
msw = insp["BlobField"] as MemoryStream;
using (FileStream file = new(@"d:\temp\blob.jpg", FileMode.Create, FileAccess.Write))
{
msw.WriteTo(file);
}
// read file into memory stream
var msr = new MemoryStream();
using (FileStream file = new(@"d:\images\Hydrant.jpg", FileMode.Open, FileAccess.Read))
{
file.CopyTo(msr);
}
//put the memory stream in the blob field and save to feature
var op = new EditOperation() { Name = "Blob Inspector" };
insp["Blobfield"] = msr;
op.Modify(insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});await QueuedTask.Run(() =>
{
var editOp = new EditOperation() { Name = "Blob Cursor" };
var featLayer = activeMap.FindLayers("Hydrant").First() as FeatureLayer;
editOp.Callback((context) =>
{
using (var rc = featLayer.GetTable().Search(null, false))
{
while (rc.MoveNext())
{
using (var record = rc.Current)
{
//read the blob field and save to a file
var msw = new MemoryStream();
msw = record["BlobField"] as MemoryStream;
using (FileStream file = new(@"d:\temp\blob.jpg", FileMode.Create, FileAccess.Write))
{
msw.WriteTo(file);
}
//read file into memory stream
var msr = new MemoryStream();
using (FileStream file = new(@"d:\images\Hydrant.jpg", FileMode.Open, FileAccess.Read))
{
file.CopyTo(msr);
}
//put the memory stream in the blob field and save to feature
record["BlobField"] = msr;
record.Store();
}
}
}
}, featLayer.GetTable());
if (!editOp.IsEmpty)
{
var result = editOp.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});
}await QueuedTask.Run(() =>
{
var sel = MapView.Active.Map.GetSelection();
//Read a raster from a raster field as an InteropBitmap
//the bitmap can then be used as an imagesource or written to disk
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
var ibmp = insp["Photo"] as System.Windows.Interop.InteropBitmap;
});await QueuedTask.Run(() =>
{
var sel = MapView.Active.Map.GetSelection();
//Insert an image into a raster field
//Image will be written with no compression
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
insp["Photo"] = @"e:\temp\Hydrant.jpg";
var op = new EditOperation() { Name = "Raster Inspector" };
op.Modify(insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});await QueuedTask.Run(() =>
{
//Open the raster dataset on disk and create a compressed raster value dataset object
var dataStore = new ArcGIS.Core.Data.FileSystemDatastore(new ArcGIS.Core.Data.FileSystemConnectionPath(new Uri(@"e:\temp"), ArcGIS.Core.Data.FileSystemDatastoreType.Raster));
using (var fileRasterDataset = dataStore.OpenDataset<ArcGIS.Core.Data.Raster.RasterDataset>("Hydrant.jpg"))
{
var storageDef = new ArcGIS.Core.Data.Raster.RasterStorageDef();
storageDef.SetCompressionType(ArcGIS.Core.Data.Raster.RasterCompressionType.JPEG);
storageDef.SetCompressionQuality(90);
var rv = new ArcGIS.Core.Data.Raster.RasterValue();
rv.SetRasterDataset(fileRasterDataset);
rv.SetRasterStorageDef(storageDef);
var sel = MapView.Active.Map.GetSelection();
//insert a raster value object into the raster field
var insp = new ArcGIS.Desktop.Editing.Attributes.Inspector();
insp.Load(sel.ToDictionary().Keys.First(), sel.ToDictionary().Values.First());
insp["Photo"] = rv;
var op = new EditOperation() { Name = "Raster Inspector" };
op.Modify(insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
}
});Handles key down events for the tool, enabling or toggling sketch selection mode when specific keys are pressed.
protected override async void OnToolKeyDown(MapViewKeyEventArgs k)
{
//toggle sketch selection mode with a custom key
if (k.Key == System.Windows.Input.Key.W)
{
if (!_inSelMode)
{
k.Handled = true;
// Toggle the tool to select mode.
// The sketch is saved if UseSelection = true;
if (await ActivateSelectAsync(true))
_inSelMode = true;
}
}
else if (!_inSelMode)
{
//disable effect of Shift in the base class.
//Mark the key event as handled to prevent further processing
k.Handled = IsShiftKey(k);
}
}
/// <summary>
/// Handles the key up events for the tool, toggling sketch selection mode off when the W key is released.
/// </summary>
protected override void OnToolKeyUp(MapViewKeyEventArgs k)
{
if (k.Key == System.Windows.Input.Key.W)
{
if (_inSelMode)
{
_inSelMode = false;
k.Handled = true;//process this one
// Toggle back to sketch mode. If UseSelection = true
// the sketch will be restored
ActivateSelectAsync(false);
}
}
else if (_inSelMode)
{
//disable effect of Shift in the base class.
//Mark the key event as handled to prevent further processing
k.Handled = IsShiftKey(k);
}
}//UseSelection = true; (UseSelection must be set to true in the tool constructor or tool activate)
private bool _inSelMode = false;
private bool IsShiftKey(MapViewKeyEventArgs k)
{
return k.Key == System.Windows.Input.Key.LeftShift ||
k.Key == System.Windows.Input.Key.RightShift;
}// Occurs when a sketch is modified. SketchModified event is fired by
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true
// Handles the SketchModified event, providing access to the current and previous sketch geometries when a sketch
// is modified.
// Register for the SketchModified event
SketchModifiedEvent.Subscribe(sketchModifiedEventArgs
=>
{
// if not an undo operation
if (!sketchModifiedEventArgs.IsUndo)
{
// what was the sketch before the change?
var prevSketch = sketchModifiedEventArgs.PreviousSketch;
// what is the current sketch?
var currentSketch = sketchModifiedEventArgs.CurrentSketch;
if (currentSketch is Polyline polyline)
{
// Examine the current (last) vertex in the line sketch
var lastSketchPoint = polyline.Points.Last();
// do something with the last point
}
}
});// Occurs before a sketch is completed. BeforeSketchCompleted event is fired by
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true
// Register for the BeforeSketchCompleted event
BeforeSketchCompletedEvent.Subscribe(beforeSketchCompletedEventArgs
=>
{
//assign sketch Z values from default surface and set the sketch geometry
var modifiedSketch = beforeSketchCompletedEventArgs.MapView.Map.GetZsFromSurfaceAsync(beforeSketchCompletedEventArgs.Sketch).Result;
beforeSketchCompletedEventArgs.SetSketchGeometry(modifiedSketch.Geometry);
return Task.CompletedTask;
});// Occurs when a sketch is completed. SketchCompleted event is fired by
// - COTS construction tools (except annotation, dimension geometry types),
// - Edit Vertices, Reshape, Align Features
// - 3rd party tools with FireSketchEvents = true
// Register for the SketchCompleted event
SketchCompletedEvent.Subscribe(sketchCompletedEventArgs
=>
{
// get the sketch
var finalSketch = sketchCompletedEventArgs.Sketch;
// do something with the sketch - audit trail perhaps
});Represents a custom map construction tool that enables sketching of all types of geometries (points, lines, polygons) with snapping and template support in ArcGIS Pro. ProSnippetConstructionToolLine is a specialized MapTool class configured for creating line geometries
public class ProSnippetConstructionToolLine : MapTool
{
public ProSnippetConstructionToolLine()
{
IsSketchTool = true;
UseSnapping = true;
// Select the type of construction tool you wish to implement.
// Make sure that the tool is correctly registered with the correct component category type in the daml
SketchType = SketchGeometryType.Line;
//Gets or sets whether the sketch is for creating a feature and should use the CurrentTemplate.
UsesCurrentTemplate = true;
// set FireSketchEvents property to true
FireSketchEvents = true;
}
// ...Within the specialization of a MapTool, this method handles activation and deactivation of the tool, allowing customization of sketch segment and vertex symbology when the tool becomes active. When the tool is activated, this method customizes the appearance of sketch segments and vertices by updating their symbol options. This includes setting colors, widths, marker types, and other visual properties for both segments and regular unselected vertices.
protected override Task OnToolActivateAsync(bool active)
{
QueuedTask.Run(() =>
{
//Getting the current symbology options of the segment
var segmentOptions = GetSketchSegmentSymbolOptions();
//Modifying the primary and secondary color and the width of the segment symbology options
var deepPurple = new CIMRGBColor() { R = 75, G = 0, B = 110 };
segmentOptions.PrimaryColor = deepPurple;
segmentOptions.Width = 4;
segmentOptions.HasSecondaryColor = true;
var pink = new CIMRGBColor() { R = 219, G = 48, B = 130 };
segmentOptions.SecondaryColor = pink;
//Creating a new vertex symbol options instance with the values you want
var vertexOptions = new VertexSymbolOptions(VertexSymbolType.RegularUnselected);
var yellow = new CIMRGBColor() { R = 255, G = 215, B = 0 };
var purple = new CIMRGBColor() { R = 148, G = 0, B = 211 };
vertexOptions.AngleRotation = 45;
vertexOptions.Color = yellow;
vertexOptions.MarkerType = VertexMarkerType.Star;
vertexOptions.OutlineColor = purple;
vertexOptions.OutlineWidth = 3;
vertexOptions.Size = 5;
//Setting the value of the segment symbol options
SetSketchSegmentSymbolOptions(segmentOptions);
//Setting the value of the vertex symbol options of the regular unselected vertices using the vertexOptions instance created above.
SetSketchVertexSymbolOptions(VertexSymbolType.RegularUnselected, vertexOptions);
});
return base.OnToolActivateAsync(active);
}// daml entries
//
// <menus>
// <menu id="MyMenu" caption="Nav">
// <button refID="esri_mapping_prevExtentButton"/>
// <button refID="esri_mapping_fixedZoomInButton"/>
// </menu>
// </menus>
// <miniToolbars>
// <miniToolbar id="MyMiniToolbar">
// <row>
// <button refID="esri_mapping_fixedZoomInButton"/>
// <button refID="esri_mapping_prevExtentButton"/>
// </row>
// </miniToolbar>
// </miniToolbars>
/// <summary>
/// Represents a map sketch tool that provides a custom context menu and mini toolbar for user interactions.
/// </summary>
/// <remarks>This tool enables line sketching on the map and displays a context menu and mini toolbar, as
/// specified by their respective DAML IDs, when activated. The context menu and toolbar can be customized to include
/// commands relevant to the sketch workflow. The tool is configured to output line geometry directly to the map.
/// <para> The <see cref="MapTool.ContextMenuID"/> and <see cref="MapTool.ContextToolbarID"/> properties are set to
/// reference custom DAML menu and mini toolbar definitions. Ensure that the specified IDs correspond to valid DAML
/// entries in your add-in configuration. </para></remarks>
public class SketchToolWithToolbar : MapTool
{
public SketchToolWithToolbar()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Line;
SketchOutputMode = SketchOutputMode.Map;
ContextMenuID = "MyMenu";
ContextToolbarID = "MyMiniToolbar";
}
}Represents a map tool that enables line sketching with a predefined sketch tip.
public class SketchToolWithSketchTip : MapTool
{
public SketchToolWithSketchTip()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Line;
SketchOutputMode = SketchOutputMode.Map;
SketchTip = "hello World";
}
}// 1. Add an embeddable control using VS template. This is the daml entry
//<categories>
// <updateCategory refID = "esri_embeddableControls">
// <insertComponent id="SketchTip_EmbeddableControl1" className="EmbeddableControl1ViewModel">
// <content className = "EmbeddableControl1View"/>
// </insertComponent>
// </updateCategory>
// </categories>
// 2. Define UI controls on the EmbeddableControl1View
// 3. Define properties on the EmbeddableControl1ViewModel which
// bind to the UI controls on the EmbeddableControl1View
/// <summary>
/// Represents a map sketch tool that displays a custom UI sketch tip using an embeddable control.
/// </summary>
public class SketchToolWithUISketchTip : MapTool
{
public SketchToolWithUISketchTip()
{
IsSketchTool = true;
SketchType = SketchGeometryType.Line;
SketchOutputMode = SketchOutputMode.Map;
SketchTipID = "SketchTip_EmbeddableControl1";
}
protected override Task<bool> OnSketchModifiedAsync()
{
var sketchTipVM = SketchTipEmbeddableControl as EmbeddableControl1ViewModel;
if (sketchTipVM != null)
{
// modify properties on the sketchTipVM
QueuedTask.Run(async () =>
{
var sketch = await GetCurrentSketchAsync();
var line = sketch as Polyline;
var count = line.PointCount;
sketchTipVM.Text = "Vertex Count " + count.ToString();
});
}
return base.OnSketchModifiedAsync();
}
}
/// <summary>
/// Represents the view model for an embeddable control, providing data and configuration options for the control's
/// behavior and appearance.
/// </summary>
/// <remarks>This class is typically used to supply options and state to an embeddable control within the
/// ArcGIS Pro framework. It is constructed with configuration data and a flag indicating whether options can be
/// changed at runtime.</remarks>
public class EmbeddableControl1ViewModel : ArcGIS.Desktop.Framework.Controls.EmbeddableControl
{
public EmbeddableControl1ViewModel(XElement options, bool canChangeOptions) : base(options, canChangeOptions)
{ }
public string Text;
}bool enableSnapping = true;
//enable snapping
Snapping.IsEnabled = enableSnapping;// set only Point and Edge snapping modes, clear everything else
Snapping.SetSnapModes(
new List<SnapMode>() { SnapMode.Point, SnapMode.Edge });
// clear all snap modes
Snapping.SetSnapModes(null);
// set snap modes one at a time
Snapping.SetSnapMode(SnapMode.Edge, true);
Snapping.SetSnapMode(SnapMode.End, true);
Snapping.SetSnapMode(SnapMode.Intersection, true);
// get current snap modes
var snapModes = Snapping.SnapModes;
// get state of a specific snap mode
bool isOn = Snapping.GetSnapMode(SnapMode.Vertex);var featureLayer = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();
// is the layer snappable?
bool isSnappable = featureLayer.IsSnappable;
// set snappability for a specific layer - needs to run on the MCT
await QueuedTask.Run(() =>
{
// use an extension method
featureLayer.SetSnappable(true);
// or use the CIM directly
//var layerDef = fLayer.GetDefinition() as ArcGIS.Core.CIM.CIMGeoFeatureLayerBase;
//layerDef.Snappable = true;
//fLayer.SetDefinition(layerDef);
});
// turn all layers snappability off
var layerList = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
await QueuedTask.Run(() =>
{
foreach (var layer in layerList)
{
layer.SetSnappable(false);
}
});var featureLayerList = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
// configure layer snap modes - must run on the MCT
await QueuedTask.Run(() =>
{
// configure by layer
foreach (var layer in featureLayerList)
{
// find the state of the snapModes for the layer
var lsm = Snapping.GetLayerSnapModes(layer);
bool vertexOn = lsm.Vertex;
// or use
vertexOn = lsm.GetSnapMode(SnapMode.Vertex);
bool edgeOn = lsm.Edge;
// or use
edgeOn = lsm.GetSnapMode(SnapMode.Edge);
bool endOn = lsm.End;
// or use
endOn = lsm.GetSnapMode(SnapMode.End);
// update a few snapModes
// turn Vertex off
lsm.SetSnapMode(SnapMode.Vertex, false);
// intersections on
lsm.SetSnapMode(SnapMode.Intersection, true);
// and set back to the layer
Snapping.SetLayerSnapModes(layer, lsm);
// assign a single snap mode at once
Snapping.SetLayerSnapModes(layer, SnapMode.Vertex, false);
// turn ALL snapModes on
Snapping.SetLayerSnapModes(layer, true);
// turn ALL snapModes off
Snapping.SetLayerSnapModes(layer, false);
}
// configure for a set of layers
// set Vertex, edge, end on for a set of layers, other snapModes false
var vee = new LayerSnapModes(false)
{
Vertex = true,
Edge = true,
End = true
};
Snapping.SetLayerSnapModes(featureLayerList, vee);
// ensure intersection is on for a set of layers without changing any other snapModes
// get the layer snapModes for the set of layers
var dictLSM = Snapping.GetLayerSnapModes(featureLayerList);
foreach (var layer in dictLSM.Keys)
{
var lsm = dictLSM[layer];
lsm.Intersection = true;
}
Snapping.SetLayerSnapModes(dictLSM);
// set all snapModes off for a list of layers
Snapping.SetLayerSnapModes(featureLayerList, false);
});// interested in only snapping to the vertices of a specific layer of interest and not the vertices of other layers
// all other snapModes should be off.
// snapping must be on
Snapping.IsEnabled = true;
// turn all application snapModes off
Snapping.SetSnapModes(null);
// set application snapMode vertex on
Snapping.SetSnapMode(SnapMode.Vertex, true);
// ensure layer snapping is on
await QueuedTask.Run(() =>
{
featureLayer.SetSnappable(true);
});
// set vertex snapping only
var vertexOnly = new LayerSnapModes(false) { Vertex = true };
// set vertex only for the specific layer, clearing all others
var dict = new Dictionary<Layer, LayerSnapModes>();
dict.Add(featureLayer, vertexOnly);
Snapping.SetLayerSnapModes(dict, true); // true = reset other layersvar myMap = MapView.Active.Map;
// Set snapping options via get/set options
var snapOptions = Snapping.GetOptions(myMap);
snapOptions.IsSnapToSketchEnabled = true;
snapOptions.XYTolerance = 100;
snapOptions.IsZToleranceEnabled = true;
snapOptions.ZTolerance = 0.6;
// turn on snap tip display parts
snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayLayer + (int)SnapTipDisplayPart.SnapTipDisplayType;
// turn off all snaptips
// snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayNone;
// turn on layer display only
// snapOptions.SnapTipDisplayParts = (int)SnapTipDisplayPart.SnapTipDisplayLayer;
snapOptions.SnapTipColor = ColorFactory.Instance.RedRGB;
Snapping.SetOptions(myMap, snapOptions);// Finds and retrieves specific editing templates by name from layers in the active map.
await QueuedTask.Run(() =>
{
var mainTemplate = activeMap.FindLayers("main").FirstOrDefault()?.GetTemplate("Distribution");
var mhTemplate = activeMap.FindLayers("Manhole").FirstOrDefault()?.GetTemplate("Active");
});// retrieve editing templates associated with standalone tables in the active map.
await QueuedTask.Run(() =>
{
//Get a particular table template
var tableTemplate = activeMap.FindStandaloneTables("Address Points").FirstOrDefault()?.GetTemplate("Residences");
//Get all the templates of a standalone table
var ownersTableTemplates = activeMap.FindStandaloneTables("Owners").FirstOrDefault()?.GetTemplates();
var statisticsTableTemplates = activeMap.GetStandaloneTablesAsFlattenedList().First(l => l.Name.Equals("Trading Statistics")).GetTemplates();
});// Retrieves the currently active editing template.
EditingTemplate template = EditingTemplate.Current;await QueuedTask.Run(() =>
{
// Get all templates for the layer
var templates = featureLayer.GetTemplates();
if (templates.Count == 0)
return;
// Get the first template - alternatively get a specific template
var template = templates.First();
// Activate the default tool
template.ActivateDefaultToolAsync();
});await QueuedTask.Run(() =>
{
// DAML ID of the tool to activate - for example "esri_editing_SketchTwoPointLineTool" Pro Tool or a custom tool
string _editToolname = "esri_editing_SketchTwoPointLineTool";
// Get all templates for the layer
var templates = featureLayer.GetTemplates();
if (templates.Count == 0)
return;
// Get the first template - alternatively get a specific template
var template = templates.First();
// Confirm the tool is available in the template
if (template.ToolIDs.FirstOrDefault(_editToolname) == null)
return;
// Activate the tool
template.ActivateToolAsync(_editToolname);
});await QueuedTask.Run(() =>
{
// Get all templates for the layer
var templates = featureLayer.GetTemplates();
if (templates.Count == 0)
return;
// Get the first template - alternatively get a specific template
var template = templates.First();
// Activate the last selected/used tool for the template
template.ActivateLastSelectedToolAsync();
});await QueuedTask.Run(() =>
{
// Get all templates for the layer
var templates = featureLayer.GetTemplates();
if (templates.Count == 0)
return;
// Get the first template - alternatively get a specific template
var template = templates.First();
// Activate the template without changing the current tool
template.ActivateAsync();
});await QueuedTask.Run(() =>
{
var templateName = "Distribution"; // name of the template to update
var toolDamlPlugInID = "esri_editing_SketchTwoPointLineTool"; // DAML ID of the tool to set as default
var toolContentGUID = "e2096d13-b437-4bc1-94ea-4494c3260f72"; // Example GUID, replace with actual GUID from DAML
// retrieve the edit template form the layer by name
var template = featureLayer?.GetTemplate(templateName) as EditingTemplate;
// get the definition of the layer
var layerDef = featureLayer?.GetDefinition() as CIMFeatureLayer;
if (template == null || layerDef == null)
return;
if (template.DefaultToolID != toolDamlPlugInID)
{
bool updateLayerDef = false;
if (layerDef.AutoGenerateFeatureTemplates)
{
layerDef.AutoGenerateFeatureTemplates = false;
updateLayerDef = true;
}
// retrieve the CIM edit template definition
var templateDef = template.GetDefinition();
// assign the GUID from the tool DAML definition, for example
// <tool id="TestConstructionTool_SampleSDKTool" categoryRefID="esri_editing_construction_polyline" ….>
// <tooltip heading="">Tooltip text<disabledText /></tooltip>
// <content guid="e58239b3-9c69-49e5-ad4d-bb2ba29ff3ea" />
// </tool>
// then the toolContentGUID would be "e58239b3-9c69-49e5-ad4d-bb2ba29ff3ea"
//templateDef.ToolProgID = toolContentGUID;
templateDef.DefaultToolGUID = toolContentGUID;
// set the definition back to
template.SetDefinition(templateDef);
// update the layer definition too
if (updateLayerDef)
featureLayer.SetDefinition(layerDef);
}
});await QueuedTask.Run(() =>
{
//hide all tools except line tool on a given feature layer
var editTemplates = featureLayer.GetTemplates();
var newCIMEditingTemplates = new List<CIMEditingTemplate>();
foreach (var et in editTemplates)
{
//initialize template by activating default tool
et.ActivateDefaultToolAsync();
var cimEditTemplate = et.GetDefinition();
//get the visible tools on this template
var allTools = et.ToolIDs.ToList();
//add the hidden tools on this template
allTools.AddRange(cimEditTemplate.GetExcludedToolIDs().ToList());
//hide all the tools then allow the line tool
allTools.AddRange(cimEditTemplate.GetExcludedToolIDs().ToList());
cimEditTemplate.SetExcludedToolIDs(allTools.ToArray());
cimEditTemplate.AllowToolID("esri_editing_SketchLineTool");
newCIMEditingTemplates.Add(cimEditTemplate);
}
//update the layer templates
var layerDef = featureLayer.GetDefinition() as CIMFeatureLayer;
// Set AutoGenerateFeatureTemplates to false for template changes to stick
layerDef.AutoGenerateFeatureTemplates = false;
layerDef.FeatureTemplates = newCIMEditingTemplates.ToArray();
featureLayer.SetDefinition(layerDef);
});await QueuedTask.Run(() =>
{
var newFieldValues = new object[] { "Value1", 123, DateTime.Now };
// Creates a new editing template for the specified feature layer with the provided field values.
var insp = new Inspector();
insp.LoadSchema(featureLayer);
insp["Field1"] = newFieldValues[0];
insp["Field2"] = newFieldValues[1];
insp["Field3"] = newFieldValues[2];
var tags = new[] { "Polygon", "tag1", "tag2" };
// set defaultTool using a daml-id
string defaultTool = "esri_editing_SketchCirclePolygonTool";
// tool filter is the tools to filter OUT
var toolFilter = new[] { "esri_editing_SketchTracePolygonTool" };
// create a new template
var newTemplate = featureLayer.CreateTemplate("My new template", "description", insp, defaultTool, tags, toolFilter);
});// Creates new table templates for the specified standalone table.
await QueuedTask.Run(() =>
{
var table = activeMap.GetStandaloneTablesAsFlattenedList().FirstOrDefault();
var tableTemplate = table.GetTemplate("Template1");
var definition = tableTemplate.GetDefinition();
definition.Description = "New definition";
definition.Name = "New name";
//Create new table template using this definition
table.CreateTemplate(definition);
//You can also create a new table template using this extension method. You can use this method the same way you use the layer.CreateTemplate method.
table.CreateTemplate("New template name", "Template description", tags: ["tag 1", "tag 2"]);
});// Updates the definition of a specified table template by modifying its name and description.
var table = activeMap.GetStandaloneTablesAsFlattenedList().FirstOrDefault();
await QueuedTask.Run(() =>
{
// get a table template
var tableTemplate = table.GetTemplate("Template1") ?? throw new Exception("No table template named 'Template1' found");
// get the definition
var definition = tableTemplate.GetDefinition();
definition.Description = "New definition";
definition.Name = "New name";
// update the definition
tableTemplate.SetDefinition(definition);
});// Creates a new annotation template for the specified annotation layer.
await QueuedTask.Run(() =>
{
Inspector insp = null;
// get the anno feature class
var fc = annotationLayer.GetFeatureClass() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClass;
// get the feature class CIM definition which contains the labels, symbols
var cimDefinition = fc.GetDefinition() as ArcGIS.Core.Data.Mapping.AnnotationFeatureClassDefinition;
var labels = cimDefinition.GetLabelClassCollection();
var symbols = cimDefinition.GetSymbolCollection();
// make sure there are labels, symbols
if (labels.Count == 0 || symbols.Count == 0)
return;
// find the label class required
// typically you would use a subtype name or some other characteristic
// in this case lets just use the first one
var label = labels[0];
// each label has a textSymbol
// the symbolName *should* be the symbolID to be used
var symbolName = label.TextSymbol.SymbolName;
int symbolID = -1;
if (!int.TryParse(symbolName, out symbolID))
{
// int.TryParse fails - attempt to find the symbolName in the symbol collection
foreach (var symbol in symbols)
{
if (symbol.Name == symbolName)
{
symbolID = symbol.ID;
break;
}
}
}
// no symbol?
if (symbolID == -1)
return;
// load the schema
insp = new Inspector();
insp.LoadSchema(annotationLayer);
// ok to assign these fields using the inspector[fieldName] methodology
// these fields are guaranteed to exist in the annotation schema
insp["AnnotationClassID"] = label.ID;
insp["SymbolID"] = symbolID;
// set up some additional annotation properties
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
annoProperties.FontSize = 36;
annoProperties.TextString = "My Annotation feature";
annoProperties.VerticalAlignment = VerticalAlignment.Top;
annoProperties.HorizontalAlignment = HorizontalAlignment.Justify;
insp.SetAnnotationProperties(annoProperties);
var tags = new[] { "Annotation", "tag1", "tag2" };
// use daml-id rather than guid
string defaultTool = "esri_editing_SketchStraightAnnoTool";
// tool filter is the tools to filter OUT
var toolFilter = new[] { "esri_editing_SketchCurvedAnnoTool" };
// create a new template
var newTemplate = annotationLayer.CreateTemplate("new annotation template", "description", insp, defaultTool, tags, toolFilter);
});// Removes predefined editing templates associated with the specified standalone table.
await QueuedTask.Run(() =>
{
var tableTemplate = table.GetTemplate("Template1");
//Removing a table template
table.RemoveTemplate(tableTemplate);
//Removing a template by name
table.RemoveTemplate("Template2");
});// Subscribes to the active template changed event and handles changes to the editing template.
ArcGIS.Desktop.Editing.Events.ActiveTemplateChangedEvent.Subscribe(async activeTemplateChangedEventArgs
=>
{
// return if incoming template is null
if (activeTemplateChangedEventArgs.IncomingTemplate == null)
return;
// Activate two-point line tool for Freeway template in the Layers map
if (activeTemplateChangedEventArgs.IncomingTemplate.Name == "Freeway" && activeTemplateChangedEventArgs.IncomingMapView.Map.Name == "Layers")
await activeTemplateChangedEventArgs.IncomingTemplate.ActivateToolAsync("esri_editing_SketchTwoPointLineTool");
});// programmatically activates the Edit Annotation tool by invoking the corresponding
// plugin. The tool must be enabled for the operation to succeed.
{
var plugin = FrameworkApplication.GetPlugInWrapper("esri_editing_EditVerticesText");
if (plugin.Enabled)
((ICommand)plugin).Execute(null);
}await QueuedTask.Run(() =>
{
// annotationLayer is ~your~ Annotation layer...
// annotationPoint is ~your~ Annotation's location geometry ...
var op = new EditOperation();
// Use the inspector
var insp = new Inspector();
insp.LoadSchema(annotationLayer);
// get the annotation properties from the inspector
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// change the annotation text
annoProperties.TextString = DateTime.Now.ToLongTimeString();
// change font color to green
annoProperties.Color = ColorFactory.Instance.GreenRGB;
// change the horizontal alignment
annoProperties.HorizontalAlignment = HorizontalAlignment.Center;
annoProperties.Shape = annotationPoint;
// set the annotation properties back on the inspector
insp.SetAnnotationProperties(annoProperties);
// create the annotation
op.Create(annotationLayer, insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Updates the text of an annotation feature in the specified annotation layer.
await QueuedTask.Run(() =>
{
// annotationLayer is ~your~ Annotation layer...
// use the inspector methodology
var insp = new Inspector();
insp.Load(annotationLayer, objectId);
// get the annotation properties
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// set the attribute
annoProperties.TextString = annotationText;
// assign the annotation properties back to the inspector
insp.SetAnnotationProperties(annoProperties);
//create and execute the edit operation
EditOperation op = new EditOperation();
op.Name = "Update annotation";
op.Modify(insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});// Modifies the geometry of an annotation feature in the specified annotation layer.
await QueuedTask.Run(() =>
{
//Don't use 'Shape'....Shape is the bounding box of the annotation text. This is NOT what you want...
//
//var insp = new Inspector();
//insp.Load(annotationLayer, objectId);
//var shape = insp["SHAPE"] as Polygon;
//...wrong shape...
//Instead, we must use the AnnotationProperties
//annotationLayer is ~your~ Annotation layer
var insp = new Inspector();
insp.Load(annotationLayer, objectId);
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
var shape = annoProperties.Shape;
if (shape.GeometryType != GeometryType.GeometryBag)
{
var newGeometry = GeometryEngine.Instance.Move(shape, 10, 10);
annoProperties.Shape = newGeometry;
insp.SetAnnotationProperties(annoProperties);
EditOperation op = new EditOperation
{
Name = "Change annotation angle"
};
op.Modify(insp);
if (!op.IsEmpty)
{
var result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
}
});// Modifies the text graphic of a selected annotation feature in the specified annotation layer.
await QueuedTask.Run(() =>
{
var selection = annotationLayer.GetSelection();
if (selection.GetCount() == 0)
return;
// use the first selected feature
var insp = new Inspector();
insp.Load(annotationLayer, selection.GetObjectIDs().FirstOrDefault());
// getAnnoProperties should return null if not an annotation feature
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// get the textGraphic
CIMTextGraphic textGraphic = annoProperties.TextGraphic;
// change text
textGraphic.Text = "Hello world";
// set x,y offset via the symbol
var symbol = textGraphic.Symbol.Symbol;
var textSymbol = symbol as CIMTextSymbol;
textSymbol.OffsetX = 2;
textSymbol.OffsetY = 3;
textSymbol.HorizontalAlignment = HorizontalAlignment.Center;
// load the updated textGraphic
annoProperties.LoadFromTextGraphic(textGraphic);
// assign the annotation properties back
insp.SetAnnotationProperties(annoProperties);
EditOperation op = new EditOperation
{
Name = "modify symbol"
};
op.Modify(insp);
if (!op.IsEmpty)
{
bool result = op.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
});//In your config.daml...set the categoryRefID
//<tool id="..." categoryRefID="esri_editing_construction_annotation" caption="Create Anno" ...>
//Sketch type Point or Line or BezierLine in the constructor...
public class ProSnippetAnnotationConstructionTool : MapTool
{
public ProSnippetAnnotationConstructionTool()
{
IsSketchTool = true;
UseSnapping = true;
SketchType = SketchGeometryType.Point;
}
/// <summary>
/// Handles the completion of a sketch operation and creates an annotation feature based on the provided geometry.
/// </summary>
protected async override Task<bool> OnSketchCompleteAsync(Geometry geometry)
{
if (CurrentTemplate == null || geometry == null)
return false;
// Create an edit operation
var createOperation = new EditOperation
{
Name = string.Format("Create {0}", CurrentTemplate.Layer.Name),
SelectNewFeatures = true
};
var insp = CurrentTemplate.Inspector;
var result = await QueuedTask.Run(() =>
{
// get the annotation properties class
AnnotationProperties annoProperties = insp.GetAnnotationProperties();
// set custom annotation properties
annoProperties.TextString = "my custom text";
annoProperties.Color = ColorFactory.Instance.RedRGB;
annoProperties.FontSize = 24;
annoProperties.FontName = "Arial";
annoProperties.HorizontalAlignment = HorizontalAlignment.Right;
annoProperties.Shape = geometry;
// assign annotation properties back to the inspector
insp.SetAnnotationProperties(annoProperties);
// Queue feature creation
createOperation.Create(CurrentTemplate.Layer, insp);
if (!createOperation.IsEmpty)
{
// Execute the operation
return createOperation.Execute(); //Execute and ExecuteAsync will return true if the operation was successful and false if not
}
else
return false;
});
return result;
}
}// Executes an edit operation and demonstrates how to undo the operation programmatically.
await QueuedTask.Run(() =>
{
var editOp = new EditOperation
{
Name = "My Name"
};
if (!editOp.IsEmpty)
{
//Execute and ExecuteAsync will return true if the operation was successful and false if not
var result = editOp.Execute();
if (result == true)
{
// If the operation was successful, you can undo it
editOp.UndoAsync();
}
}
});// Demonstrates how to undo and redo the most recent operation using the map's operation manager.
//undo
if (activeMap.OperationManager.CanUndo)
activeMap.OperationManager?.UndoAsync();//await as needed
//redo
if (MapView.Active.Map.OperationManager.CanRedo)
activeMap.OperationManager?.RedoAsync();//await as needed
}// Retrieves and processes the list of available topologies in the active map.
await QueuedTask.Run(async () =>
{
var map = MapView.Active.Map;
//Get a list of all the available topologies for the map
var availableTopologies = await map.GetAvailableTopologiesAsync();
var gdbTopologies = availableTopologies.OfType<GeodatabaseTopologyProperties>();
var mapTopologies = availableTopologies.OfType<MapTopologyProperties>();
});// Retrieves the properties of the active topology associated with the specified map asynchronously.
var activeTopologyProperties = await activeMap.GetActiveTopologyAsync();
var isMapTopology = activeTopologyProperties is MapTopologyProperties;
var isGdbTopology = activeTopologyProperties is GeodatabaseTopologyProperties;
var isNoTopology = activeTopologyProperties is NoTopologyProperties;// Retrieves the topology properties for the specified map asynchronously.
var mapTopoProperties = await activeMap.GetTopologyAsync("Map") as MapTopologyProperties;
var tolerance_m = mapTopoProperties.Tolerance;
var defaultTolerance_m = mapTopoProperties.DefaultTolerance;// Asynchronously retrieves the properties of a geodatabase topology with the specified name from the given map.
var topoProperties = await activeMap.GetTopologyAsync(topologyName) as GeodatabaseTopologyProperties;
var workspace = topoProperties.WorkspaceName;
var topoLayer = topoProperties.TopologyLayer;
var clusterTolerance = topoProperties.ClusterTolerance;// Sets the topology of the specified map as the current map topology asynchronously.
if (activeMap.CanSetMapTopology())
{
//Set the topology of the map as map topology
var mapTopoProperties = await activeMap.SetMapTopologyAsync() as MapTopologyProperties;
}// Removes the current topology from the specified map asynchronously, setting it to have no topology.
if (activeMap.CanClearTopology())
{
//Clears the topology of the map - no topology
await activeMap.ClearTopologyAsync();
}// Sets the active topology for the specified map to the topology with the given name asynchronously.
if (activeMap.CanSetActiveTopology(topologyName))
{
await activeMap.SetActiveTopologyAsync(topologyName);
}// Sets the active topology for the specified map using the provided geodatabase topology properties.
var gdbTopoProperties = await activeMap.GetTopologyAsync("TopologyName") as GeodatabaseTopologyProperties;
if (activeMap.CanSetActiveTopology(gdbTopoProperties))
{
await activeMap.SetActiveTopologyAsync(gdbTopoProperties);
}// Builds the map topology graph for the active map view and displays the number of topology nodes and edges.
await QueuedTask.Run(() =>
{
//Build the map topology graph
MapView.Active.BuildMapTopologyGraph<TopologyDefinition>(topologyGraph =>
{
//Getting the nodes and edges present in the graph
var topologyGraphNodes = topologyGraph.GetNodes();
var topologyGraphEdges = topologyGraph.GetEdges();
foreach (var node in topologyGraphNodes)
{
// do something with the node
}
foreach (var edge in topologyGraphEdges)
{
// do something with the edge
}
MessageBox.Show($"Number of topo graph nodes are: {topologyGraphNodes.Count}.\n Number of topo graph edges are {topologyGraphEdges.Count}.", "Map Topology Info");
});
});// Retrieves the SelectionSet from a command that was added and executed from the Attribute Pane Context Menu
await QueuedTask.Run(async () =>
{
var selSet = FrameworkApplication.ContextMenuDataContextAs<SelectionSet>();
if (selSet == null)
return;
int count = selSet.Count;
if (count == 0)
return;
var op = new EditOperation
{
Name = "Delete context"
};
op.Delete(selSet);
await op.ExecuteAsync();
});bool isCorecting = correction.IsCorrecting(); // equivalent to correction != null && correction.Enabled;
bool UsingOffset = correction.UsingDirectionOffset(); // equivalent to correction.IsCorrecting() && correction.UseDirection;
double dOffset = correction.GetDirectionOffset(); // equivalent to correction.UsingDirectionOffset() ? correction.Direction : DefaultDirectionOffset;
bool usingDistanceFactor = correction.UsingDistanceFactor(); // equivalent to correction.IsCorrecting() && correction.UseScale;
bool usingElevation = correction.UsingElevationMode(); // equivalent to correction.UsingDistanceFactor() && c.ScaleType == GroundToGridScaleType.ComputeUsingElevation;
bool usingSFactor = correction.UsingConstantScaleFactor(); //; equivalent to correction.UsingDistanceFactor() && correction.ScaleType == GroundToGridScaleType.ConstantFactor;
double dSFactor = correction.GetConstantScaleFactor(); // equivalent to correctionc.UsingDistanceFactor() ? correction.ConstantScaleFactor : DefaultConstantScaleFactor;//toggle, switch Editing option values
var options = ApplicationOptions.EditingOptions;
options.EnforceAttributeValidation = !options.EnforceAttributeValidation;
options.WarnOnSubtypeChange = !options.WarnOnSubtypeChange;
options.InitializeDefaultValuesOnSubtypeChange = !options.InitializeDefaultValuesOnSubtypeChange;
options.UncommitedAttributeEdits = (options.UncommitedAttributeEdits ==
UncommitedEditMode.AlwaysPrompt) ? UncommitedEditMode.Apply : UncommitedEditMode.AlwaysPrompt;
options.StretchGeometry = !options.StretchGeometry;
options.StretchTopology = !options.StretchTopology;
options.UncommitedGeometryEdits = (options.UncommitedGeometryEdits ==
UncommitedEditMode.AlwaysPrompt) ? UncommitedEditMode.Apply : UncommitedEditMode.AlwaysPrompt;
options.ActivateMoveAfterPaste = !options.ActivateMoveAfterPaste;
options.ShowFeatureSketchSymbology = !options.ShowFeatureSketchSymbology;
options.FinishSketchOnDoubleClick = !options.FinishSketchOnDoubleClick;
options.AllowVertexEditingWhileSketching = !options.AllowVertexEditingWhileSketching;
options.ShowDeleteDialog = !options.ShowDeleteDialog;
options.EnableStereoEscape = !options.EnableStereoEscape;
options.DragSketch = !options.DragSketch;
options.ShowDynamicConstraints = !options.ShowDynamicConstraints;
options.IsDeflectionDefaultDirectionConstraint =
!options.IsDeflectionDefaultDirectionConstraint;
options.IsDirectionDefaultInputConstraint = !options.IsDirectionDefaultInputConstraint;
options.ShowEditingToolbar = !options.ShowEditingToolbar;
options.ToolbarPosition = (options.ToolbarPosition == ToolbarPosition.Bottom) ?
ToolbarPosition.Right : ToolbarPosition.Bottom;
options.ToolbarSize = (options.ToolbarSize == ToolbarSize.Medium) ?
ToolbarSize.Small : ToolbarSize.Medium;
options.MagnifyToolbar = !options.MagnifyToolbar;
options.EnableEditingFromEditTab = !options.EnableEditingFromEditTab;
options.AutomaticallySaveEdits = !options.AutomaticallySaveEdits;
options.AutoSaveByTime = !options.AutoSaveByTime;
options.SaveEditsInterval = (options.AutomaticallySaveEdits) ? 20 : 10;
options.SaveEditsOperations = (options.AutomaticallySaveEdits) ? 60 : 30;
options.SaveEditsOnProjectSave = !options.SaveEditsOnProjectSave;
options.ShowSaveEditsDialog = !options.ShowSaveEditsDialog;
options.ShowDiscardEditsDialog = !options.ShowDiscardEditsDialog;
options.DeactivateToolOnSaveOrDiscard = !options.DeactivateToolOnSaveOrDiscard;
options.NewLayersEditable = !options.NewLayersEditable;// A fallback tool is the tool that will be activated when an editing tool
// is deactivated; (when the Escape key press for example)
// To register a tool as a fallback tool, add the following into your
// add-in's config.daml file
// <updateModule refID = "esri_editing_EditingModule">
// <menus>
// <updateMenu refID = "esri_editing_DefaultTools">
// <insertButton refID = "MyAddIn_MyCustomTool"/>
// </updateMenu>
// </menus>
// </updateModule>
var options = ApplicationOptions.EditingOptions;
// get the list of fallback tools that are registered
var fallbackTools = options.GetFallbackTools();
// get the current fallback tool
var fallbackTool = options.FallbackTool;
// set the fallback tool
// (MyAddIn_MyCustomTool must be added to the "esri_editing_DefaultTools" list)
options.FallbackTool = "MyAddIn_MyCustomTool";var eOptions = ApplicationOptions.EditingOptions;
var followLinkedLines = eOptions.AutomaticallyFollowLinkedLineFeatures;
var followLinedPolygons = eOptions.AutomaticallyFollowLinkedPolygonFeatures;
var usePlacementProps = eOptions.UseAnnotationPlacementProperties;
var followMode = eOptions.AnnotationFollowMode;
var placementMode = eOptions.AnnotationPlacementMode;
eOptions.AnnotationFollowMode = AnnotationFollowMode.Parallel;
eOptions.AnnotationPlacementMode = AnnotationPlacementMode.Left;var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
//There are 4 vertex symbol settings - selected, unselected and the
//current vertex selected and unselected.
var reg_select = options.GetVertexSymbolOptions(VertexSymbolType.RegularSelected);
var reg_unsel = options.GetVertexSymbolOptions(VertexSymbolType.RegularUnselected);
var curr_sel = options.GetVertexSymbolOptions(VertexSymbolType.CurrentSelected);
var curr_unsel = options.GetVertexSymbolOptions(VertexSymbolType.CurrentUnselected);
//to convert the options to a symbol use
//GetPointSymbol
var reg_sel_pt_symbol = reg_select.GetPointSymbol();
//ditto for reg_unsel, curr_sel, curr_unsel
});var options = ApplicationOptions.EditingOptions;
//var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
var seg_options = options.GetSegmentSymbolOptions();
//to convert the options to a symbol use
//SymbolFactory. Note: this is approximate....sketch isn't using the
//CIM directly for segments
var layers = new List<CIMSymbolLayer>();
var stroke0 = SymbolFactory.Instance.ConstructStroke(seg_options.PrimaryColor,
seg_options.Width, SimpleLineStyle.Dash);
layers.Add(stroke0);
if (seg_options.HasSecondaryColor)
{
var stroke1 = SymbolFactory.Instance.ConstructStroke(
seg_options.SecondaryColor, seg_options.Width, SimpleLineStyle.Solid);
layers.Add(stroke1);
}
//segment symbology only
var sketch_line = new CIMLineSymbol()
{
SymbolLayers = layers.ToArray()
};
});var options = ApplicationOptions.EditingOptions;
//var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
//change the regular unselected vertex symbol
//default is a green, hollow, square, 5pts. Change to
//Blue outline diamond, 10 pts
var vertexSymbol = new VertexSymbolOptions(VertexSymbolType.RegularUnselected);
vertexSymbol.OutlineColor = ColorFactory.Instance.BlueRGB;
vertexSymbol.MarkerType = VertexMarkerType.Diamond;
vertexSymbol.Size = 10;
//Are these valid?
if (options.CanSetVertexSymbolOptions(
VertexSymbolType.RegularUnselected, vertexSymbol))
{
//apply them
options.SetVertexSymbolOptions(VertexSymbolType.RegularUnselected, vertexSymbol);
}
});var options = ApplicationOptions.EditingOptions;
//var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
//change the segment symbol primary color to green and
//width to 1 pt
var segSymbol = options.GetSegmentSymbolOptions();
segSymbol.PrimaryColor = ColorFactory.Instance.GreenRGB;
segSymbol.Width = 1;
//Are these valid?
if (options.CanSetSegmentSymbolOptions(segSymbol))
{
//apply them
options.SetSegmentSymbolOptions(segSymbol);
}
});var options = ApplicationOptions.EditingOptions;
//var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
//ditto for reg selected and current selected, unselected
var def_reg_unsel =
options.GetDefaultVertexSymbolOptions(VertexSymbolType.RegularUnselected);
//apply default
options.SetVertexSymbolOptions(
VertexSymbolType.RegularUnselected, def_reg_unsel);
});var options = ApplicationOptions.EditingOptions;
//var options = ApplicationOptions.EditingOptions;
await QueuedTask.Run(() =>
{
var def_seg = options.GetDefaultSegmentSymbolOptions();
options.SetSegmentSymbolOptions(def_seg);
});var vOptions = ApplicationOptions.VersioningOptions;
vOptions.DefineConflicts = (vOptions.DefineConflicts == ConflictDetectionType.ByRow) ?
ConflictDetectionType.ByColumn : ConflictDetectionType.ByRow;
vOptions.ConflictResolution = (
vOptions.ConflictResolution == ConflictResolutionType.FavorEditVersion) ?
ConflictResolutionType.FavorTargetVersion : ConflictResolutionType.FavorEditVersion;
vOptions.ShowConflictsDialog = !vOptions.ShowConflictsDialog;
vOptions.ShowReconcileDialog = !vOptions.ShowReconcileDialog;
Home | API Reference | Requirements | Download | Samples | Snippets
-
Edit Operation - check for actions before Execute
-
Edit Operation Create Features
-
Create a feature using the current template
-
Create feature from a modified inspector
-
Create features from a CSV file
-
Edit Operation Create row in a table using a table template
-
Edit Operation Clip Features
-
Edit Operation Cut Features
-
Edit Operation Delete Features
-
Edit Operation Duplicate Features
-
Edit Operation Explode Features
-
Edit Operation Merge Features
-
Edit Operation Modify single feature
-
Edit Operation Modify multiple features
-
Search for layer features and update a field
-
Move features
-
Move feature to a specific coordinate
-
Edit Operation Planarize Features
-
Edit Operation ParallelOffset
-
Edit Operation Reshape Features
-
Edit Operation Rotate Features
-
Edit Operation Scale Features
-
Edit Operation Split Features
-
Edit Operation: Transfer Attributes
-
Edit Operation Transform Features
-
Edit Operation Rubbersheet Features
-
Edit Operation Perform a Clip, Cut, and Planarize
-
Edit Operation Chain Edit Operations
-
Edit Operation add attachment via RowToken
-
Order edits sequentially
-
SetOnUndone, SetOnRedone, SetOnComitted
-
Convert vertices in a polyline to a Control Point
-
Start a Single workspace edit session via a MapMember
-
Start a single workspace edit session - Full example
-
Start a Single workspace edit session via a DatastoreConfiguration
-
Subscribe to Row Events
-
Create a record in a separate table in the Map within Row Events
-
Create a record in a separate table within Row Events
-
Modify a record within Row Events - using Row.Store
-
Modify a record within Row Events - using EditOperation.Modify
-
Determine if Geometry Changed while editing
-
Cancel a delete
-
Load a feature from a layer into the inspector
-
Load map selection into Inspector
-
Get selected feature's attribute value
-
Load map selection into Inspector and Change Attributes
-
Get a layers schema using Inspector
-
Inspector.AddValidate
-
Read and Write blob fields with the attribute inspector
-
Read and Write blob fields with a row cursor in a callback
-
Read from a raster field
-
Write an image to a raster field
-
Write a compressed image to a raster field
-
Listen to the sketch modified event
-
Listen to the before sketch completed event and modify the sketch
-
Listen to the sketch completed event
-
Custom construction tool that fires sketch events
-
Customizing the Sketch Symbol of a Custom Sketch Tool
-
Configure Snapping - Turn Snapping on or off
-
Configure Snapping - Application SnapModes
-
Configure Snapping - Layer Snappability
-
Configure Snapping - LayerSnapModes
-
Configure Snapping - Combined Example
-
Snap Options
-
Find edit template by name on a layer
-
Find table templates belonging to a standalone table
-
Current template
-
Activate template and its default editing tool
-
Activate template and a specific editing tool
-
Activate template and it's last selected tool
-
Activate template without changing current tool
-
Change Default Edit tool for a template
-
Hide or show editing tools on templates
-
Create New Template using layer.CreateTemplate
-
Create New Table Template using table.CreateTemplate
-
Update a Table Template
-
Create Annotation Template
-
Remove a table template
-
Active Template Changed
-
Programmatically start Edit Annotation
-
Programmatically Create an Annotation Feature
-
Update Annotation Text
-
Modify Annotation Shape
-
Modify Annotation Text Graphic
-
Annotation Construction Tool
-
Get List of available topologies in the map
-
Get the properties of the active topology in the map
-
Get map topology properties
-
Get geodatabase topology properties by name
-
Set Map Topology as the current topology
-
Set 'No Topology' as the current topology
-
Set the current topology by name
-
Set the current topology by topologyProperties
-
Get/Set Editing Options
-
Default or Fallback Tools
-
Get/Set Editing Annotation Options
-
Get Sketch Vertex Symbology Options
-
Get Sketch Segment Symbology Options
-
Set Sketch Vertex Symbol Options
-
Set Sketch Segment Symbol Options
-
Set Sketch Vertex Symbol Back to Default
-
Set Sketch Segment Symbol Back to Default