Where to listen for OnRowChanged event

3603
14
Jump to solution
04-08-2019 11:33 AM
BrianBulla
Occasional Contributor III

Hi,

I'm trying to implement some code in an AddIn that will listen for Edit events, and then run some code.  I'm using the following article to help (https://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic9808.html) but I'm not sure where I am supposed to put this code.

Should I be creating a new AddIn for this, or can I just add the code to an existing AddIn?  All users currently load the same Toolbar, which I have created an AddIn for.  Can I just put the code in there??

Thanks,

14 Replies
BrianBulla
Occasional Contributor III

Hi Sean Jones‌,

Thanks for the tip on the 1.1 sample.  That has definitely helped.  I've now got it working so that it works for all layers in the opened project.  As you said, I'll need to add some code for added/removed layers, new maps, etc. but I'm on the right path now.

What I'm realizing is that I don't need to Subscribe to EVERY layer in every map.  I only need to subscribe to the layers from a particular server, or even more specifically, those that are Versioned.  Any tips on determining if the current FeatureLayer is versioned??  It doesn't appear to be in the FeatureClassDefinition.  Where should I be looking for this??

 

Thanks!!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Threading.Tasks;
using ArcGIS.Core.CIM;
using ArcGIS.Core.Data;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Catalog;
using ArcGIS.Desktop.Core;
using ArcGIS.Desktop.Editing;
using ArcGIS.Desktop.Extensions;
using ArcGIS.Desktop.Framework;
using ArcGIS.Desktop.Framework.Contracts;
using ArcGIS.Desktop.Framework.Dialogs;
using ArcGIS.Desktop.Framework.Threading.Tasks;
using ArcGIS.Desktop.Mapping;
using ArcGIS.Desktop.Editing.Events;
using ArcGIS.Desktop.Core.Events;

namespace RowChanged_TEST
{
    internal class Module1 : Module
    {
        private static Module1 _this = null;
        private bool fakeEdit = false;

        /// <summary>
        /// Retrieve the singleton instance to this module here
        /// </summary>
        public static Module1 Current
        {
            get
            {
                return _this ?? (_this = (Module1)FrameworkApplication.FindModule("RowChanged_TEST_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()
        {
            ProjectOpenedEvent.Subscribe(onProjectOpened);

            //var eceToken = EditCompletedEvent.Subscribe(onEce);
            return base.Initialize();
        }

       private void onProjectOpened(ProjectEventArgs args)
        {
            //Subscribe to the EditCompleted event....maybe I don't need this??
            EditCompletedEvent.Subscribe(onEce);            

            //1.  Loop to go through each Map in the project
            //2.  Loop to go through each layer in each Map

            //Need to edit this so only ones we need are accounted for!!
            QueuedTask.Run(() =>
            {
                foreach (MapProjectItem mapItem in Project.Current.GetItems<MapProjectItem>())
                {
                    var theMap = mapItem.GetMap();

                    foreach (FeatureLayer fLayer in theMap.GetLayersAsFlattenedList().OfType<FeatureLayer>())
                    {
                        var layerTable = fLayer.GetTable();                        
                        var rowChangedToken = RowChangedEvent.Subscribe(OnRowChanged, layerTable);
                    }
                }
            });
        }
        
        protected Task onEce(EditCompletedEventArgs args)
        {
            return Task.FromResult(0);
        }

        private Guid _currentRowChangedGuid = Guid.Empty;

        protected void OnRowChanged(RowChangedEventArgs args)
        {
            var row = args.Row;

            if (_currentRowChangedGuid == args.Guid)
                return;

            row["LASTUSER"] = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
            row["DATEMODIFIED"] = DateTime.Now.ToString();

            //_currentRowChangedGuid = args.Guid;
            //row.Store();
            _currentRowChangedGuid = Guid.Empty;
        }

        #endregion Overrides
    }
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
by Anonymous User
Not applicable

Hey Brian,

You can determine the version type from the GetRegistrationType method on a dataset.

QueuedTask.Run(() =>
{
  //get selected layer in toc
  var featLayer = MapView.Active.GetSelectedLayers().First() as FeatureLayer;

  //get geodatabase type
  var gdbType = ((Geodatabase)featLayer.GetFeatureClass().GetDatastore()).GetGeodatabaseType();

  //get registration type
  var regType = featLayer.GetFeatureClass()?.GetRegistrationType();

  var gdbInfo = string.Format("Layer: {0}\nGDBType: {1}\nGDBReg: {2}", featLayer.ToString(), gdbType.ToString(), regType.ToString());
  MessageBox.Show(gdbInfo);
});
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
MarcusPolivirus
New Contributor

Hello,

I'm trying to achieve almost the same as you.

After a "reconcile" then a "post", i want to list all changes posted to the "default" version (for all versioned layers).

So far I subscribed to EditCompletedEvent and then logs what's happening.

System.Diagnostics.Debug.WriteLine("Operation type = " + args.CompletedType);
System.Diagnostics.Debug.WriteLine("Creates: " + args.Creates.Values.Sum(list => list.Count).ToString());
System.Diagnostics.Debug.WriteLine("Modifies: " + args.Modifies.Values.Sum(list => list.Count).ToString());
System.Diagnostics.Debug.WriteLine("Deletes: " + args.Deletes.Values.Sum(list => list.Count).ToString());

On a new version, I modify a feature located in a versioned layer.

When I save 

CompletedType = Operation

args.Modifies.Values.Sum(list => list.Count) = 1

When I reconcile

CompletedType = Reconcile

args.Modifies.Values.Sum(list => list.Count) = 0

When I post

CompletedType = Post

args.Modifies.Values.Sum(list => list.Count) = 0

I would like to know why there is nothing in Modifies when I post.

It means I should save all the changes (Rows) in memory, in a dictionary for example (and in a file for persistence if the user close ArcGIS Pro) and when I detect a Post, i save the old values (the ones saved in the dictionary / file) in an other FeatureClass and let the process continues to save in the default version. Looks like what Brian did by subscribing to the RowChangedEvent of each Layer.

Is it possible to detect when the Post of one element did complete ?

Let's say, I made a huge modification on my version and the Post will take minutes. If I close ArcGIS Pro, ArcGIS Pro crashes or I lost the connection with the database, what will happen, a rollback, only X items will be updated ?

0 Kudos
by Anonymous User
Not applicable

Marcus,

Modifies, Creates and deletes are only recorded for the 'operation' completed type.

The 'version differences' function in the UI and SDK may help.
You can also listen to row changes in the parent table but you would have to time it so you know the changes are coming from the post.

Post is an all or nothing operation so if it fails half way through, nothing will be updated.

0 Kudos
MarcusPolivirus
New Contributor

Hello Sean,

Thanks for putting me on the right path with the  'version differences' thing.

Did not know about that Github repo ProConcepts Geodatabase · Esri/arcgis-pro-sdk Wiki · GitHub  but it really helps.

Will try asap, thanks again.

This other thread looks also promising.

0 Kudos