Select to view content in your preferred language

Edit event for Utility Network

1165
7
07-11-2022 07:45 PM
OscarYam
Occasional Contributor

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?

0 Kudos
7 Replies
Aashis
by Esri Contributor
Esri Contributor

@OscarYam Could you please share your feature creation code snippet so we can answer you correctly?

0 Kudos
OscarYam
Occasional Contributor

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 

	}
0 Kudos
RichRuh
Esri Regular Contributor

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

OscarYam
Occasional Contributor

Is it possible to create an attribute rule that obtains a sequence number from SQL Server and assigns it to an attribute?

0 Kudos
RichRuh
Esri Regular Contributor

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

0 Kudos
OscarYam
Occasional Contributor

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.

0 Kudos
OscarYam
Occasional Contributor

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?

0 Kudos