Select to view content in your preferred language

Bug in Geoprocessing.ExecuteToolAsync / management.AddField ?

3727
8
07-08-2016 09:12 AM
HoriaTudosie
Frequent Contributor

In my application I have two gdb_s with two layers with the same name on the same Map.

(Don't ask me why: this is how the client wants and my project manager has enforced the specs.

Previously I have put them on separate MapViews and synchronized the views...)

I diferenciate the two layers by the presence of the db_operation field, and edit accordingly their symbology:

To a certain point, I have to check the second layer and add additional fields.

This is the code:

private async Task<bool> ExecuteAddFieldTool(KeyValuePair<string, string> field, string fieldType, int? fieldLength = null, bool isNullable = true)
        {
            try
            {
                var inTable = DeltaLayer.Name;
                var workspaceName = ((IInternalMapMember)DeltaLayer).WorkspaceName;


                var parameters = Geoprocessing.MakeValueArray(inTable, field.Key, fieldType.ToUpper(), null, null,
                    fieldLength, field.Value, isNullable ? "NULABLE" : "NON_NULLABLE");
                var env = Geoprocessing.MakeEnvironmentArray(workspace: workspaceName);
                var cts = new CancellationTokenSource();
                var results = Geoprocessing.ExecuteToolAsync("management.AddField",
                    parameters, env, cts.Token, (eventName, o) =>
                    {
                        switch (eventName)
                        {
                            case "OnValidate":
                                if (((IGPMessage[])o).Any(it => it.Type == GPMessageType.Warning))
                                {
                                    var fieldExists = ((IGPMessage[])o).FirstOrDefault(it => it.ErrorCode == 12);
                                    if (fieldExists != null)
                                    {
                                        //MessageBox.Show($"{fieldExists.Text}");
                                        cts.Cancel();
                                    }
                                }
                                break;
                        }
                    });
                await results;
                return true;
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.ToString());
                return false;
            }
        }

When calling this method, DeltaLayer points to the second table and env:workspacename computes to the right gdb name (line 11.)

However the fields got added to the first layer!

Am I doing something wrong, or is a bug I cannot control?

Also related:

It is a pain into *** to have same layer names!

The related Add or Deleting-Field Geoprocessing tools have a way to differentiate layers with same names:

           

However the Content does not use this technique, and neither the Attribute Table(s):

(I still differentiate them by the presence of the db_operation field, but it is the 90th column in the above grid!)

0 Kudos
8 Replies
HoriaTudosie
Frequent Contributor

It happens also when trying to delete directly from the attribute tables:

then:

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I added a new sample to community sample repo: https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Geodatabase/AddDeleteFieldToFro...

I also tested this sample with a scenario similar to yours by adding two feature classes that are stored in to different geodatabases to my map using the same layer name.  The sample changes the top most layer, I added the new field and it worked as expected:

s1.png

Next I moved my second top layer to the top and added a new field here as well:s2.png

Finally I deleted the latest newly added field which worked as expected:

s3.png

Maybe you can try the sample and see if it works with your data.

0 Kudos
HoriaTudosie
Frequent Contributor

Hi Wolfgang,

I'm surely going to try the sample and repeat the tests today.

However, for now, I want to point out that my first comment has nothing to do with coding:

I have placed the two gdbs aside in the content on the same mapView. Then from each of them I have right click and selected Attribute Table.

Selected the second one, right-click on the header of a field which exists in both of them and selected Delete.

DeleteField.png

The field in the table which I have right-clicked remains, however the one in the table/layer which appears first in the content has been deleted.

(I have just tried again and it reproduces!)

That was done without code, using just the UI of ArcGis Pro 1.3!

This behavior reproduces what happens in my code...

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi Horia,

My sample always looks at the top most layer to perform its actions (add/delete field) and that seems to work.  When I tried your scenario from the user interface by deleting a field of the layer that is not the top most layer (with your given setup) I also noticed that the field in the top most layer was deleted instead of the field in the layer that I had chosen.  We relayed the scenario to the appropriate developers and I will try a small modification to my sample to check if the behavior fails programmatically as well.

Thanks Wolfgang

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

I modified the sample to use the 'selected' layer for the add/delete operations and it appears the same problem you discovered in the Pro UI exists even when I programmatically change the schema - the schema change is always executed on the top most layer (given your pre-conditions).  Everything works as expected after I make the layer name unique.  Maybe for the time being you can append a string to your layer names (like ... "RoadSegment (production)" and "RoadSegment (proposed)" ) in order to work around this issue until a fix is available.

0 Kudos
HoriaTudosie
Frequent Contributor

Unfortunately, as much pain as it gives, I cannot change layer names: is it part of the specks as these layers may come from unknown providers.

However I could move the operation layer on the top...

0 Kudos
HoriaTudosie
Frequent Contributor

Hi Wolfgang,

Please note some strange behaviors related to the title of the popup:

Firstly, the dialog Pop-up / Title Options has no save option/button. Not sure, but I feel that it is saving only when exiting ArgGis Pro 1.3.

Then: when not involved any code, maybe related to having same layer names from different geodatabases: the pop-up window will get the title specks from the first layer in the Contents disregarding the layer the feature belong to.

When using custom code: there is no option to specify a Title on custom content, but this time, the title comes from the second layer in the content (Or the standard one: the one showing the layer name and the object ID, though the object Id comes as <null>,) again disregarding the layer the feature which generates the custom content comes from!

 

And this is my code inherited from Community Samples:

(Sorry the Advance Editor is making a mess from this document on formatting as C#!)

using System;

using System.Collections.Generic;

using System.IO;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Input;

using System.Windows.Media.Imaging;

using ArcGIS.Core.Geometry;

using ArcGIS.Desktop.Framework.Threading.Tasks;

using ArcGIS.Desktop.Mapping;

using GFXModule.Properties;

namespace GFXModule

{

    /// <summary>

    /// Implementation of custom pop-up tool.

    /// </summary>

    internal class PickupTool : MapTool

    {

        /// <summary>

        /// Define the tool as a sketch tool that draws a rectangle in screen space on the view.

        /// </summary>

        public PickupTool()

        {

            IsSketchTool = true;

            switch(Settings.Default.GfxPickOption)

            {

                case PickToolOptions.Point:

                    SketchType = SketchGeometryType.Point;

                    Cursor = GetCursor("PointCursor.cur");

                    break;

                case PickToolOptions.Rectangle:

                    SketchType = SketchGeometryType.Rectangle;

                    Cursor = GetCursor("RectangleCursor.cur");

                    break;

                case PickToolOptions.Circle:

                    SketchType = SketchGeometryType.Circle;

                    Cursor = GetCursor("CircleCursor.cur");

                    break;

            }

            UseSnapping = true;

            //Cursor = Cursors.Arrow;

            SketchOutputMode = SketchOutputMode.Screen; //required for 3D selection and identify.

        }

        private static Cursor GetCursor(string imagesCursorCur)

        {

            try

            {

                var streamResourceInfo = Application.GetResourceStream(new Uri(@"pack://application:,,,/GFXModule;component/Images/"+imagesCursorCur));

                if (streamResourceInfo != null)

                    return new Cursor(

                        streamResourceInfo.Stream

                        );

            }

            catch (IOException)

            {

            }

            catch (UriFormatException)

            {

            }

            return Cursors.Cross;

        }

        /// <summary>

        /// Called when a sketch is completed.

        /// </summary>

        protected override async Task<bool> OnSketchCompleteAsync(Geometry geometry)

        {

            if (Module1.GfxViewModel == null) return false;

            var popupContent = await QueuedTask.Run(() =>

            {

                var mapView = MapView.Active;

                if (mapView == null)

                    return null;

                //Get the features that intersect the sketch geometry.

                var result = mapView.GetFeatures(geometry);

                //For each feature in the result create a new instance of our custom popup content class.

                List<PopupContent> popups = new List<PopupContent>();

                foreach (var kvp in result)

                {

                    kvp.Value.ForEach(id => popups.Add(new GfxPopupContent(kvp.Key, id, kvp.Key == Module1.GfxViewModel.DeltaLayer)));

                }

                //Flash the features that intersected the sketch geometry.

                mapView.FlashFeature(result);

                //return the collection of popup content object.

                return popups;

            });

            //Show the custom pop-up with the custom commands and the default pop-up commands.

            MapView.Active.ShowCustomPopup(popupContent, CreateCommands(), true);

            return true;

        }

        /// <summary>

        /// Create and return a new collection of popup commands

        /// </summary>

        /// <returns></returns>

        private List<PopupCommand> CreateCommands()

        {

            var commands = new List<PopupCommand>

            {

                new PopupCommand(OnPopupCommand, CanExecutePopupCommand,

                    "Pair this",

                    new BitmapImage(new Uri("pack://application:,,,/GFXModule;component/Images/Pickup16.png")))

                {

                    IsSeparator = true

                }

            };

            //Add a new instance of a popup command passing in the delegate to be run when the button is clicked.

            return commands;

        }

        /// <summary>

        /// The method called when the custom popup command is clicked.

        /// </summary>

        void OnPopupCommand(PopupContent content)

        {

            //Cast the content parameter to our custom popup content class.

            var dynamicContent = content as GfxPopupContent;

            //Call a method on the custom popup content object to show some statistics for the current popup content.

            dynamicContent?.PairFeature();

        }

        /// <summary>

        /// The method called periodically by the framework to determine if the command should be enabled.

        /// </summary>

        bool CanExecutePopupCommand(PopupContent content)

        {

            return

                content != null

                && content.MapMember.Map.Name.StartsWith("Delta Map");

        }

    }

}

(I should add the code for GfxPopupContent, but I dare not!)

0 Kudos
Wolf
by Esri Regular Contributor
Esri Regular Contributor

Hi Horia,

I verified your observations and will relay your findings to the developers.  I made a few changes to the custom popup sample https://github.com/Esri/arcgis-pro-sdk-community-samples/tree/master/Map-Exploration/CustomPopup specifically in "CustomPopupTool.cs" and this what I observed:

Line 64 instantiates DynamicPopupContent which allows me to customize each page (by overriding "OnCreateHtmlContent"):


    kvp.Value.ForEach(id => popups.Add(new DynamicPopupContent(kvp.Key, id)));

If I run the code as shown above I do observe that the Title customization is not properly applied, however if I change the code to use the "configured pop-ups" content (from the Pop-ups dock pane) then I get the proper behavior regarding the title.  This is simply done by changing line 64 as follows:  

    kvp.Value.ForEach(id => popups.Add(new PopupContent(kvp.Key, id)));

No as i scroll through my pop-up records i can see that the title changes according to what i specified on the Pop-ups dock pane for that layer. 
Finally i can also override the Title property in the overridden "OnCreateHtmlContent" method in order to correct the title as required, but this causes a flash on the title bar as the old title is overridden.