HI,
When I call Map.RemoveLayers() on a list of annotation layers, ArcGIS Pro hangs up. Any idea why?
Thanks,
Martin
Hi Rich,
Thanks. Unfortunately, I need to delete and recreate the table.
Do you need to delete and recreate the table, or just clear it out?
If deleting all the records is acceptable, you could try Table.DeleteRows(). If you pass in a default QueryFilter, this deletes all the rows in the table. Alternatively, you could use the Truncate geoprocessing tool.
--Rich
I'm starting ArcGIS Pro with command line parameters from an external driver program. The name of the ArcGIS Pro project to load is part of the command line parameters. I've installed an add-in so that when ArcGIS Pro opens, my add-in is called. I then register in my add-in for the ApplicationStartupEvent event. When this event is triggered, I then register for the ActivePaneChangedEvent event and DrawCompleteEvent event. If the user saved his Project such that the currently showing pane is not a MapView that I'm interested in, I search for the pane that I am interested in the ActivePaneChangedEvent event handler and Activate it so that the MapView I"m interested in will show up and draw.
Your assumptions;
1. You know which annotation tables you like to 'refresh' by name and file GDB path. - correct
1. Your 'refresh' is in essence deleting the annotation feature class first and then recreating it. - correct
1. When a mapview is opened you want it to display the 'refreshed' annotation. - this doesn't matter to me as when the user opens his Project manually, he should see the updated annotation since the annotation layer he added manually will still be there, just with new content.
Workflow:
All correct except the last three items. I'm re-creating the annotation feature class inside the ArcGIS Pro process that I launched but, I'm doing so by copying an existing template annotation feature class that the user created because there is no way to create an annotation feature class in Pro SDK (in contrast to ArcObjects) because of a bug in the management.CreateFeatureClass GP tool that was reported in 2011 but never fixed according to the GeoNet forum). Do you happen to know if I'm wrong about that? Because the Pro docs say to use the management.CreateFeatureClass tool as the only way to create an annotation feature class but the docs for the GP tool don't have an option for feature class type of annotation (if you try with "annotation", it gives an error).
I don't add the annotation layer back into the TOC since when the user re-opens his Project, his annotation layer will still be there since I don't save the Project when I shut down ArcGIS Pro after the add-in workflow is completed.
A few questions and assumption of mine regarding the workflow. I just want to make sure i understand your workflow before i try it:
Do you start Pro with a configuration or without any command line parameters? How is the ArcGIS Pro project loaded - i.e. does the user click to open a project or does your add-in/configuration open it programmatically?
Here are a few assumptions of mine, let me know if these are correct:
1. You know which annotation tables you like to 'refresh' by name and file GDB path.
1. Your 'refresh' is in essence deleting the annotation feature class first and then recreating it.
1. When a mapview is opened you want it to display the 'refreshed' annotation.
And here are my assumptions of how your workflow works:
1. A mapview pane opens and draws a map including the [from above] annotation in the TOC
1. You wait for the mapview to finish drawing
1. In the OnCompletedDrawEvent you delete the TOC entry for the annotation feature class
1. On the annotation feature class you run a Geoprocessing tool, management.Delete
1. Currently this tool hangs - but let's ignore the hang for now
1. You then recreate the a new annotation feature class using some external process - maybe a GP tool again, this annotation feature class has the same name/path as the one you deleted before.
1. You add the annotation back to the TOC.
1. Now the mapview shows the 'refreshed' annotation class.
I determined that if I set a Timer and execute my code 10 sec after the ApplicationStartupEvent event is fired, then the map.RemoveLayer() doesn't hang so as you pointed out, ArcGIS Pro isn't ready to execute that method when the ApplicationStartupEvent is fired. Do you know if there is any event fired that indicates ArcGIS Pro is done fully starting up?
Thanks for the detailed response. Unfortunately, Alt+Ctrl+M doesn't do anything once ArcGIS Pro comes up but maybe that's because its UI thread is busy in my module. But I'll look more into that Diagnostics tool.
Basically, on start-up of ArcGIS Pro, I'm deleting an annotation table and then re-creating it in order to fill it with new annotation generated by an external batch process. If the annotation table to be deleted exists in the Table of Contents, then the Geoprocessing tool, management.Delete, hangs. In order to avoid that hang, I wanted to remove the annotation layer from the TOC since when I do this manually, then the Delete GeoProcessing tool doesn't hang.
Looks like we are getting closer to the cause of the hang ... in general context matters because Pro will execute background operations in sequence and if you introduce an operation with a cross dependency this can lead to a 'hang'. You can use the ArcGIS Diagnostic Monitor (which you can start once ArcGIS Pro has started by using the following key sequence: Alt+Ctrl+M) to see any such hangs. Just as a test you can try to run your logic from the UI thread by using the following utility functions [in my case] added to a Utils class:
<SPAN class="comment token">/// <summary></SPAN> <SPAN class="comment token">/// utility function to enable an action to run on the UI thread (if not already)</SPAN> <SPAN class="comment token">/// </summary></SPAN> <SPAN class="comment token">/// <param name="action">the action to execute</param></SPAN> <SPAN class="comment token">/// <returns></returns></SPAN> <SPAN class="keyword token">internal</SPAN> <SPAN class="keyword token">static</SPAN> <SPAN class="keyword token">void</SPAN> <SPAN class="token function">RunOnUiThread</SPAN><SPAN class="punctuation token">(</SPAN>Action action<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">try</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>IsOnUiThread<SPAN class="punctuation token">)</SPAN> <SPAN class="token function">action</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">else</SPAN> Application<SPAN class="punctuation token">.</SPAN>Current<SPAN class="punctuation token">.</SPAN>Dispatcher<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Invoke</SPAN><SPAN class="punctuation token">(</SPAN>action<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="keyword token">catch</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="token class-name">Exception</SPAN> ex<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> MessageBox<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Show</SPAN><SPAN class="punctuation token">(</SPAN>$<SPAN class="string token">@"Error in RunOnUiThread: {ex.Message}"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="comment token">/// <summary></SPAN> <SPAN class="comment token">/// Determines whether the calling thread is the thread associated with this </SPAN> <SPAN class="comment token">/// System.Windows.Threading.Dispatcher, the UI thread.</SPAN> <SPAN class="comment token">/// </SPAN> <SPAN class="comment token">/// If called from a View model test it always returns true.</SPAN> <SPAN class="comment token">/// </summary></SPAN> <SPAN class="keyword token">public</SPAN> <SPAN class="keyword token">static</SPAN> <SPAN class="keyword token">bool</SPAN> IsOnUiThread <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN> ArcGIS<SPAN class="punctuation token">.</SPAN>Desktop<SPAN class="punctuation token">.</SPAN>Framework<SPAN class="punctuation token">.</SPAN>FrameworkApplication<SPAN class="punctuation token">.</SPAN>TestMode <SPAN class="operator token">||</SPAN> System<SPAN class="punctuation token">.</SPAN>Windows<SPAN class="punctuation token">.</SPAN>Application<SPAN class="punctuation token">.</SPAN>Current<SPAN class="punctuation token">.</SPAN>Dispatcher<SPAN class="punctuation token">.</SPAN><SPAN class="token function">CheckAccess</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
and using RunOnUiThread you can then run your business logic on the UI thread:
Utils<SPAN class="punctuation token">.</SPAN><SPAN class="token function">RunOnUiThread</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="comment token">// add your logic here </SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
If we take a step back though, what is it your workflow is trying to accomplish? Are you trying to programmatically remove certain layers from the TOC when a new mapview is opened ? Maybe there's a better way to do this.
Hi Wolfgang,
Ok, thanks. Then it's probably a bug then I guess as I'm not calling that code from a UI action (e.g. button click) but instead from a Module after the ApplicationStartupEvent event is fired and then after the OnCompletedDrawEvent is fired for the MapView I'm interested in.
Hi Martin,
I wasn't sure about the Wait, since I wasn't patient enough I removed it, however, it works with or without. You have to use the Datastore within a using block though. I tried the sample code below and it worked fine ... the anno layers under the group were removed and no hang occurred.
<SPAN class="keyword token">protected</SPAN> <SPAN class="keyword token">override</SPAN> <SPAN class="keyword token">async</SPAN> <SPAN class="keyword token">void</SPAN> <SPAN class="token function">OnClick</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">var</SPAN> activeMap <SPAN class="operator token">=</SPAN> MapView<SPAN class="punctuation token">.</SPAN>Active<SPAN class="operator token">?</SPAN><SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>activeMap <SPAN class="operator token">==</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="keyword token">return</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">var</SPAN> location <SPAN class="operator token">=</SPAN> <SPAN class="string token">@"C:/Data/FeatureTest/FeatureTest.gdb"</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">var</SPAN> name <SPAN class="operator token">=</SPAN> <SPAN class="string token">@"TestLinesAnno"</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">await</SPAN> QueuedTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Run</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN> <SPAN class="punctuation token">{</SPAN> List<SPAN class="operator token"><</SPAN>Layer<SPAN class="operator token">></SPAN> layersToRemove <SPAN class="operator token">=</SPAN> <SPAN class="keyword token">new</SPAN> <SPAN class="token class-name">List</SPAN><SPAN class="operator token"><</SPAN>Layer<SPAN class="operator token">></SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">foreach</SPAN> <SPAN class="punctuation token">(</SPAN>AnnotationLayer annotationLayer <SPAN class="keyword token">in</SPAN> activeMap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetLayersAsFlattenedList</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">.</SPAN>OfType<SPAN class="operator token"><</SPAN>AnnotationLayer<SPAN class="operator token">></SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">using</SPAN> <SPAN class="punctuation token">(</SPAN>AnnotationFeatureClass featureClass <SPAN class="operator token">=</SPAN> annotationLayer<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetFeatureClass</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="keyword token">as</SPAN> AnnotationFeatureClass<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>featureClass <SPAN class="operator token">!=</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">using</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="keyword token">var</SPAN> dataStore <SPAN class="operator token">=</SPAN> featureClass<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetDatastore</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>dataStore<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetPath</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">.</SPAN>AbsolutePath <SPAN class="operator token">==</SPAN> location <SPAN class="operator token">&&</SPAN> featureClass<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetName</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">==</SPAN> name<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> layersToRemove<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Add</SPAN><SPAN class="punctuation token">(</SPAN>annotationLayer<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="punctuation token">}</SPAN> activeMap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">RemoveLayers</SPAN><SPAN class="punctuation token">(</SPAN>layersToRemove<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
I'm doing something nearly the same. Here is my code:
Task removeOutputLayersTask = QueuedTask.Run(() => { List<Layer> layersToRemove = new List<Layer>(); foreach (AnnotationLayer annotationLayer in m_map.GetLayersAsFlattenedList().OfType<AnnotationLayer>()) { AnnotationFeatureClass featureClass = annotationLayer.GetFeatureClass() as AnnotationFeatureClass; using (featureClass) { if (featureClass != null) { if (featureClass.GetDatastore().GetPath().AbsolutePath == m_geodatabaseLocation && (featureClass.GetName() == m_name) { layersToRemove.Add(annotationLayer); } } } } m_map.RemoveLayers(layersToRemove);
}removeOutputLayersTask.Wait(10000);
It's hard to tell without seeing your code. I lifted this snippet from one of my samples and it works:
<SPAN class="keyword token">var</SPAN> activeMap <SPAN class="operator token">=</SPAN> MapView<SPAN class="punctuation token">.</SPAN>Active<SPAN class="operator token">?</SPAN><SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">if</SPAN> <SPAN class="punctuation token">(</SPAN>activeMap <SPAN class="operator token">==</SPAN> <SPAN class="keyword token">null</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="keyword token">return</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">try</SPAN> <SPAN class="punctuation token">{</SPAN> <SPAN class="keyword token">var</SPAN> removeLayers <SPAN class="operator token">=</SPAN> activeMap<SPAN class="punctuation token">.</SPAN><SPAN class="token function">GetLayersAsFlattenedList</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">.</SPAN>OfType<SPAN class="operator token"><</SPAN>FeatureLayer<SPAN class="operator token">></SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">.</SPAN><SPAN class="token function">Where</SPAN><SPAN class="punctuation token">(</SPAN>fl <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN> fl<SPAN class="punctuation token">.</SPAN>Name<SPAN class="punctuation token">.</SPAN><SPAN class="token function">StartsWith</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="string token">"Test"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="keyword token">await</SPAN> QueuedTask<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Run</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">(</SPAN><SPAN class="punctuation token">)</SPAN> <SPAN class="operator token">=</SPAN><SPAN class="operator token">></SPAN> <SPAN class="punctuation token">{</SPAN> MapView<SPAN class="punctuation token">.</SPAN>Active<SPAN class="punctuation token">.</SPAN>Map<SPAN class="punctuation token">.</SPAN><SPAN class="token function">RemoveLayers</SPAN><SPAN class="punctuation token">(</SPAN>removeLayers<SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN> <SPAN class="keyword token">catch</SPAN> <SPAN class="punctuation token">(</SPAN><SPAN class="token class-name">Exception</SPAN> ex<SPAN class="punctuation token">)</SPAN> <SPAN class="punctuation token">{</SPAN> MessageBox<SPAN class="punctuation token">.</SPAN><SPAN class="token function">Show</SPAN><SPAN class="punctuation token">(</SPAN>$<SPAN class="string token">@"Exception occurred: {ex}"</SPAN><SPAN class="punctuation token">)</SPAN><SPAN class="punctuation token">;</SPAN> <SPAN class="punctuation token">}</SPAN><SPAN class="line-numbers-rows"><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN><SPAN></SPAN></SPAN>
Aangemelde leden kunnen berichten plaatsen, updates volgen en meer. Nieuw hier? Registreer een gratis account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.