Open a MapPane

98
3
06-26-2022 03:30 PM
BerndtNording
New Contributor III

I want to be able to open (activate) a MapPane with a specific map if it exists, or create it if it doesn't but can't figure out how to accomplish this.

Logically, I can get all the MapPanes with this:

var mapProjItems = Project.Current.GetItems<MapProjectItem>();

Each of the MapPanes in there *should* have a map, and if I iterate through there, I can  activate the pane if the map's name is the one I want, or create a new one if it is not found. The problem is that only the MapPane that is currently active has a map, for all the others  the map property is null.

There is a Pro Snippet called "Get the Unique List of Maps From the Map Panes" and it crashes because of the same problem:

public static IReadOnlyList<Map> GetMapsFromMapPanes()
{
  //Gets the unique list of Maps from all the MapPanes.
  //Note: The list of maps retrieved from the MapPanes
  //maybe less than the total number of Maps in the project.
  //It depends on what maps the user has actually opened.
  var mapPanes = ProApp.Panes.OfType<IMapPane>()
              .GroupBy((mp) => mp.MapView.Map.URI).Select(grp => grp.FirstOrDefault());
  List<Map> uniqueMaps = new List<Map>();
  foreach (var pane in mapPanes)
    uniqueMaps.Add(pane.MapView.Map);
  return uniqueMaps;
}

 

There is another snippet called "Find a map within a project and open it", but it always creates a new MapPane (so then you have two with the same name and map) because of the same problem.

And there is also the MapProjectItem.OpenMapPane() method, but it too creates a new MapPane.

This should be so simple to do...

0 Kudos
3 Replies
NarelleChedzey
Esri Contributor

Hi Berndt, 

 

Take a look at the following snippet.  As I understand, it will achieve what you're asking for.  That is, if there is an open pane for the map it will activate it.  If there isn't a map pane, it will create / open one. 

 

private void ActivateOrOpenMapPane(string mapName)
{
   var mapProjItem = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(mp => mp.Name == mapName);
   if (mapProjItem != null)
   {
     // is it already open? - check the open panes
     var mapPane = ProApp.Panes.OfType<IMapPane>().FirstOrDefault(pane => pane.Caption == mapName);
     if (mapPane != null)
     {
       var pane = mapPane as Pane;
       pane.Activate();
     }
     else
     {
       // open a new mapPane
       mapProjItem.OpenMapPaneAsync();

       // OR use the following
       //    it does the same thing as MapProjectItem.OpenMapPaneAsync
       //QueuedTask.Run(() =>
       //{
       //  var map = mapProjItem.GetMap();
       //  ProApp.Panes.CreateMapPaneAsync(map);
       //});
     }
   }
   else
   {
     // mapName is not in the project. 
   }
}

 

I apologize for the snippet "Get the Unique List of Maps From the Map Panes" crashing.  At early releases of ArcGIS Pro the MapPane objects were always fully populated (that is the MapView and the Map could be accessed), however over the releases loading optimizations have taken place and now the Map on the MapView is only accessible after it has been the active MapView.   This is the issue that you're seeing that is causing the crash.   I will ensure that the code is removed.

 

Please let me know if the snippet provided doesn't help.

 

Narelle. 

 

0 Kudos
BerndtNording
New Contributor III

Hello Narelle,

Thanks for the quick reply! Even on a Sunday!

I tried your snippet, and it works, but only sometimes, and would thus introduce a bug into any addin that uses it.  I suspected that the pane caption is just a text property of the pane and not tied tied to the map that the pane contains, and a little test proved this to be so. It appears that the default caption is the name of the map, but if the caption is changed after the pane is created then the snippet thinks the pane doesn't exist and creates a new one. Furthermore, I need to be able to make changes to map that is not active, and was intending to use that broken snippet to get at the map. Is there another way to get at a map object since I now can't traverse down the object hierarchy to find it?

I understand the reasoning behind the change from some older version you described, but isn't the usual way ESRI deals with that would be to create a lightweight version of the map object that has only a few key properties to identify it plus a method to retrieve the fully populated map object if needed?

Also, there is no OpenMapPaneAsync.  I'm using 2.8, maybe new in 3.0?  But, OpenMapPane does work and apparently doesn't need to be run on the MCT either.

The alternative method that you commented out still relies on being able to get a map from a mapProjectItem which only works if the pane is active.

mapProjItem.OpenMapPaneAsync();

 

0 Kudos
NarelleChedzey
Esri Contributor

Hi Berndt, 

Yes, sorry.  The code I gave you was 3.0 code.   OpenMapPaneAsync was OpenMapPane in previous versions of the SDK (we added the Async suffix at 3.0 for naming consistencies). 

Rather than the name of the map / mapView / pane it is better to be using the CIM path of the map.  This is guaranteed to be unique within the project and is exposed as Map.Uri.   It is also the MapProjectItem.Path and also IMapPane.ContentID.    so the code above would be as follows if you were starting with a map name. 

 

private void ActivateOrOpenMapPane(string mapName)
{
   var mapProjItem = Project.Current.GetItems<MapProjectItem>().FirstOrDefault(mpi => mpi.Name == mapName);
   if (mapProjItem != null)
   {
     // is it already open? - check the open panes
     var mapPane = ProApp.Panes.OfType<IMapPane>().FirstOrDefault(mPane => (mPane as Pane).ContentID == mapProjItem.Path);

     if (mapPane != null)
     {
       var pane = mapPane as Pane;
       pane.Activate();
     }
     else
     {
       // open a new mapPane
       mapProjItem.OpenMapPaneAsync();

       // OR use the following
       //    it does the same thing as MapProjectItem.OpenMapPaneAsync
       //QueuedTask.Run(() =>
       //{
       //  var map = mapProjItem.GetMap();
       //  ProApp.Panes.CreateMapPaneAsync(map);
       //});
     }
   }
   else
   {
     // mapName is not in the project. 
   }
}

 

Let me know if this still doesn't execute as you expect for your workflow.

Narelle

0 Kudos