Hi, I am new to ArcGIS Pro SDK. Using ArcGIS Pro 2.9 and Utility Network version 5.
I am working on an ArcGIS Pro add-in project. I need to implement an automation function that assigns attributes when users create a new feature. For example, assign a region code by the location where the user clicked which requires a spatial query.
I tried RowCreatedEvent but it is not working on a branch versioned feature service.
How can I achieve my goal similar to the ArcObject OnCreateFeature event? If not, is there any workaround?
@OscarYam Could you please share your feature creation code snippet so we can answer you correctly?
Here is the code that I tested on both versioned and non-versioned. Which on fine on non-versioned.
internal class Module1 : Module
{
//For the events
private Dictionary<string, List<SubscriptionToken>> _rowevents = new Dictionary<string, List<SubscriptionToken>>();
private static List<SubscriptionToken> rowCreateTokens = new List<SubscriptionToken>();
private static List<SubscriptionToken> rowChangeTokens = new List<SubscriptionToken>();
private static List<SubscriptionToken> rowDeleteTokens = new List<SubscriptionToken>();
private static Module1 _this = null;
/// <summary>
/// Retrieve the singleton instance to this module here
/// </summary>
public static Module1 Current
{
get
{
return _this ?? (_this = (Module1)FrameworkApplication.FindModule("CodePan_Module"));
}
}
#region Overrides
/// <summary>
/// Called by Framework when ArcGIS Pro is closing
/// </summary>
/// <returns>False to prevent Pro from closing, otherwise True</returns>
protected override bool CanUnload()
{
//TODO - add your business logic
//return false to ~cancel~ Application close
return true;
}
protected override bool Initialize()
{
EditTemplateEvent();
ActiveMapViewChangedEvent.Subscribe(OnActiveMapViewChanged);
return base.Initialize();
}
private async void OnActiveMapViewChanged(ActiveMapViewChangedEventArgs activeMapViewChangedEventArgs)
{
await subscribeToRowEvent();
}
void EditTemplateEvent()
{
ActiveTemplateChangedEvent.Subscribe(OnActiveTemplateChanged);
void OnActiveTemplateChanged(ActiveTemplateChangedEventArgs args)
{
// return if incoming template is null
if (args.IncomingTemplate == null)
{
return;
}
string templateName = args.IncomingTemplate.Name;
var insp = args.IncomingTemplate.Inspector;
switch (templateName)
{
case "Point":
insp["Field"] = $"{templateName} test";
break;
case "Line":
insp["Field"] = $"{templateName} test";
break;
case "Polygon":
insp["Field"] = $"{templateName} test";
break;
}
QueuedTask.Run(() => {
args.IncomingTemplate.ActivateDefaultToolAsync();
});
}
}
protected Task subscribeToRowEvent()
{
return QueuedTask.Run(() =>
{
if (MapView.Active != null && MapView.Active.Map != null)
{
var editLayers = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>();
if (editLayers.Count() == 0)
{
return;
}
foreach (var layer in editLayers)
{
//Listen for row events on a layer
var layerTable = layer.GetTable();
//subscribe to row events
SubscriptionToken rowCreateToken = RowCreatedEvent.Subscribe(onRowCreateEvent, layerTable);
SubscriptionToken rowChangeToken = RowChangedEvent.Subscribe(onRowChangeEvent, layerTable);
SubscriptionToken rowDeleteToken = RowDeletedEvent.Subscribe(onRowDeleteEvent, layerTable);
rowCreateTokens.Add(rowCreateToken);
rowChangeTokens.Add(rowChangeToken);
rowDeleteTokens.Add(rowDeleteToken);
}
}
});
}
protected void onRowCreateEvent(RowChangedEventArgs args)
{
//MessageBox.Show("onRowCreateEvent " + args.EditType.ToString());
Row row = args.Row;
Feature feature = args.Row as Feature;
Geometry editGeometry = feature["Shape"] as Geometry;
FeatureLayer featureLayer = MapView.Active.Map.FindLayers("DSDDistrict", false).OfType<FeatureLayer>().First(l => l.Name.Equals("DSDDistrict"));
SpatialQueryFilter spatialQueryFilter = new SpatialQueryFilter
{
FilterGeometry = editGeometry,
SpatialRelationship = SpatialRelationship.Intersects
};
RowCursor rowCursor = featureLayer.Search(spatialQueryFilter);
string region = "";
while (rowCursor.MoveNext())
{
Row districtRow = rowCursor.Current;
region = districtRow["DIV"] as string;
}
row["Field"] = $"CUSTOM VALUE {region}";
row.Store();
}
protected void onRowChangeEvent(RowChangedEventArgs args)
{
//MessageBox.Show("onRowChangeEvent " + args.EditType.ToString());
}
protected void onRowDeleteEvent(RowChangedEventArgs args)
{
//MessageBox.Show("onRowDeleteEvent " + args.EditType.ToString());
}
#endregion Overrides
}
I'll add that you should take a look at attribute rules. These are scripts that you can configure on a geodatabase that run in response to edit events on specific feature classes or subtypes. Doing a spatial query and assigning a value to an attribute is exactly what they are designed to do.
Attribute Rules also work cross-platform, and will fire outside of ArcGIS Pro (e.g., runtime and server)
--Rich
Is it possible to create an attribute rule that obtains a sequence number from SQL Server and assigns it to an attribute?
Yes. Attribute rules are written using a scripting language called Arcade, which provides a function called GetNextSequenceValue(). More information on attribute rules can be found starting here.
--Rich
Thank you for your assistance. I'm going to study the materials that you mentioned. Hope this will work in my situation. I will update this post if I have any updates.
Now I am having a problem with getting the sequence number.
I would like to test out the basic concept before the actual implementation, so I tested on a geodatabase.
I created a File geoDatabase and created the sequence "ThePointSequence" by using Create Database Sequence tool. Then I had a test run that failed(see in the attachments).
Then I try the function GetNextSequenceValue() that you suggested. There was an Error Invalid Arcade expression.
So, is there any mistake in my testing? Or do I start on the wrong path?