I'm executing this code:
private Task ExecuteAddFieldTool(string fieldName, string fieldAlias, string fieldType, int? fieldLength=null, bool isNullable=true) { var inTable = DeltaLayer.Name; var workspaceName = ((IInternalMapMember) DeltaLayer).WorkspaceName; var parameters = Geoprocessing.MakeValueArray(inTable, fieldName, fieldType.ToUpper(), null, null, fieldLength, fieldAlias, isNullable ? "NULABLE" : "NON_NULLABLE"); var env = Geoprocessing.MakeEnvironmentArray(workspace: workspaceName); var cts = new System.Threading.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)) { MessageBox.Show($"{eventName}: {o}"); } break; case "OnMessage": case "OnProgressMessage": MessageBox.Show($"{eventName}: {o}"); //if ((string)o == "Updating...") ... break; case "OnProgressPos": MessageBox.Show($"{eventName}: {o} %"); }); return results; }
The code execute fine, and the field is created, but after the last message shown - "Updating..." the UI freezes and have to crash ArcGis Pro from Task Manager.
I can see the field created only after restarting the project in ArcGis Pro.
I have tries all kind of variation on QueuedTask, Task, Task Factory, async and await with no success!
I tried the following code (new project and simply adding an AddField button) using the sample data from the community samples (GitHub) repo and it worked without any exceptions. To catch any exceptions in your code you should always use a try {} catch () {} sequence like in my sample below.
internal class AddField : Button { protected override async void OnClick() { await ExecuteAddFieldTool("test2", "Test 2", "TEXT", 100); } private async Task<bool> ExecuteAddFieldTool(string fieldName, string fieldAlias, string fieldType, int? fieldLength = null, bool isNullable = true) { try { var inTable = @"TestLines"; var workspaceName = @"C:\Data\FeatureTest\FeatureTest.gdb"; var parameters = Geoprocessing.MakeValueArray(inTable, fieldName, fieldType.ToUpper(), null, null, fieldLength, fieldAlias, isNullable ? "NULABLE" : "NON_NULLABLE"); var env = Geoprocessing.MakeEnvironmentArray(workspace: workspaceName); var cts = new System.Threading.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)) { MessageBox.Show($"{eventName}: {o}"); } break; case "OnMessage": case "OnProgressMessage": MessageBox.Show($"{eventName}: {o}"); break; case "OnProgressPos": MessageBox.Show($"{eventName}: {o} %"); break; default: MessageBox.Show($"{eventName}: {o} %"); break; } }); await results; return true; } catch (Exception ex) { MessageBox.Show(ex.ToString()); } return false; } }
Should be something else, because from the OnClick() event of a toolbar button works,
while from my Model of my ViewModel of my MVVM pattern implementation it does not work at all now...
Investigating.
After creating three fields with a button from the extension's toolbar, none of the fields are visible in the application.
The Layer has been already applied to the map prior to this operation (in a saved project.)
The fields are actually created because they are visible to a next run of the project, and I can see the correct messages of SuccessfullyCreatedField and EndRunTool, but I HAVE to exit and start again the project to see them (as in the Table Attributes or View Fields of this. Not sure yet if I'll be able to use them in code like that...)
Is it a way to refresh the view(s) in code in the same way that the manual tools (Add Field and Delete Fields) do?