The MapFrame.Export() method returns the exception message, "MapView is not initialized"

279
2
Jump to solution
02-15-2024 09:00 AM
estz2
by
New Contributor II

Hi all, I was made aware of this bug, 'The MapFrame.Export() method returns the exception message, "MapView is not initialized" after creating a new MapFrame object on a layout in ArcGIS Pro SDK 3.1 for .NET'

But I have updated to the latest version 3.2.2 and I am still having this bug occur in my code. I am testing layouts in my arcgis add-in. Here is the code:

'''

public static async Task<string> ScreenShotMapViewAsync()
{
return await QueuedTask.Run(async () =>
{
var reportLayout = Project.Current
.GetItems<LayoutProjectItem>()
.FirstOrDefault(l => l.Name == "ReportLayout")
?.GetLayout();

reportLayout ??= await CreateMapLayout();

Map newMap = MapFactory.Instance.CreateMap(
"Census Map",
MapType.Map,
MapViewingMode.Map,
Basemap.NationalGeographic
);
string url =
@"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer";
Uri uri = new Uri(url);
LayerFactory.Instance.CreateLayer(uri, newMap);

// Build a map frame geometry / envelope
Coordinate2D ll = new Coordinate2D(1, 0.5);
Coordinate2D ur = new Coordinate2D(13, 9);
Envelope mapEnv = EnvelopeBuilderEx.CreateEnvelope(ll, ur);

// Create a map frame and add it to the layout
MapFrame newMapframe = ElementFactory.Instance.CreateMapFrameElement(
reportLayout,
mapEnv,
newMap
);
newMapframe.SetName("Map Frame");

// Create and set the camera
Camera camera = newMapframe.Camera;
camera.X = -118.465;
camera.Y = 33.988;
camera.Scale = 30000;
newMapframe.SetCamera(camera);

// Add text for title
Coordinate2D titleTxt_ll = new Coordinate2D(4.5, 9.5);
CIMTextSymbol arial36bold = SymbolFactory.Instance.ConstructTextSymbol(
ColorFactory.Instance.BlueRGB,
80,
"Arial",
"Bold"
);
GraphicElement titleTxtElm = ElementFactory.Instance.CreateTextGraphicElement(
reportLayout,
TextType.PointText,
titleTxt_ll.ToMapPoint(),
arial36bold,
"Census Data",
"Title"
);
titleTxtElm.SetName("Title");

// Add north arrow
// Reference a North Arrow in a style
StyleProjectItem stylePrjItm = Project.Current
.GetItems<StyleProjectItem>()
.FirstOrDefault(item => item.Name == "ArcGIS 2D");
NorthArrowStyleItem naStyleItm = stylePrjItm.SearchNorthArrows("ArcGIS North 8")[0];

// Set the center coordinate and create the arrow on the layout
Coordinate2D center = new Coordinate2D(15, 7);
var naInfo = new NorthArrowInfo()
{
MapFrameName = newMapframe.Name,
NorthArrowStyleItem = naStyleItm
};
var arrowElm = ElementFactory.Instance.CreateMapSurroundElement(
reportLayout,
center.ToMapPoint(),
naInfo
);

arrowElm.SetName("New North Arrow");
arrowElm.SetHeight(2);
var filePath = Path.GetTempFileName() + ".png";

PNGFormat PNG = new PNGFormat();
PNG.Resolution = 300;
PNG.OutputFileName = filePath;

if (PNG.ValidateOutputFilePath())
{
newMapframe.Export(PNG);
}

return filePath;
});

'''

The exception occurs at the line newMapFrame.Export(PNG); 
Am I doing this wrong or is the bug still present in 3.2? BUG-000157092 for ArcGIS Pro SDK for .NET (esri.com)

0 Kudos
1 Solution

Accepted Solutions
CharlesMacleod
Esri Regular Contributor

I see the issue. This is a tricky one. Because u r making a map-on-the-fly, it does not have an associated MapView. The MapView - as in the "rendering" or "display" of the map (and not the map itself - which is the "data" or model ) is what actually gets exported.....

For this to work u need to split it into 2 separate steps - or button clicks....The first step creates the map and renderers it on a MapView.  The second step, or "click" creates your layout on-the-fly and exports it. These do not have to happen, of course, in an exact sequence....the requirement for the Map frame to be exported is that the Map, at some point in time, prior to the export, has been rendered on a MapView. It does not have to "immediately" precede the export.

To create a MapView pane to render/display the map programmatically do: 

await FrameworkApplication.Panes.CreateMapPaneAsync(newMap);

 

So, in the case of your specific code example, I made two buttons - a "Create Map" and a "Create Export". The Create Map consolidates all the code to create the map, add the layer, and create a MapView.  The Create Export is, basically, everything else.

Create the map:

    protected override void OnClick()  {
      var census_map = await QueuedTask.Run(() =>
      {
        var map = MapFactory.Instance.CreateMap(
        "Census Map",
        MapType.Map,
        MapViewingMode.Map,
        Basemap.NationalGeographic
        );

        string url =
@"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer";
        Uri uri = new Uri(url);
        LayerFactory.Instance.CreateLayer(uri, map);
        return map;
      });

      FrameworkApplication.Panes.CreateMapPaneAsync(census_map);
   }
}

 

Create the export:

protected override void OnClick()
{
  //Find the map to be exported
  Map census_map = null;
  var map_panes = FrameworkApplication.Panes.OfType<IMapPane>().ToList();
  foreach(var map_pane in map_panes) {
     if (map_pane.MapView.Map.Name == "Census Map") {
       census_map = map_pane.MapView.Map;
       break;
     }
   }
   if (census_map == null) {
     //Early exit, MessageBox, etc.
   }
   await QueuedTask.Run(() => {
     //Create the layout
     //Export, etc.
   };
   ...

 

 

View solution in original post

2 Replies
CharlesMacleod
Esri Regular Contributor

I see the issue. This is a tricky one. Because u r making a map-on-the-fly, it does not have an associated MapView. The MapView - as in the "rendering" or "display" of the map (and not the map itself - which is the "data" or model ) is what actually gets exported.....

For this to work u need to split it into 2 separate steps - or button clicks....The first step creates the map and renderers it on a MapView.  The second step, or "click" creates your layout on-the-fly and exports it. These do not have to happen, of course, in an exact sequence....the requirement for the Map frame to be exported is that the Map, at some point in time, prior to the export, has been rendered on a MapView. It does not have to "immediately" precede the export.

To create a MapView pane to render/display the map programmatically do: 

await FrameworkApplication.Panes.CreateMapPaneAsync(newMap);

 

So, in the case of your specific code example, I made two buttons - a "Create Map" and a "Create Export". The Create Map consolidates all the code to create the map, add the layer, and create a MapView.  The Create Export is, basically, everything else.

Create the map:

    protected override void OnClick()  {
      var census_map = await QueuedTask.Run(() =>
      {
        var map = MapFactory.Instance.CreateMap(
        "Census Map",
        MapType.Map,
        MapViewingMode.Map,
        Basemap.NationalGeographic
        );

        string url =
@"https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer";
        Uri uri = new Uri(url);
        LayerFactory.Instance.CreateLayer(uri, map);
        return map;
      });

      FrameworkApplication.Panes.CreateMapPaneAsync(census_map);
   }
}

 

Create the export:

protected override void OnClick()
{
  //Find the map to be exported
  Map census_map = null;
  var map_panes = FrameworkApplication.Panes.OfType<IMapPane>().ToList();
  foreach(var map_pane in map_panes) {
     if (map_pane.MapView.Map.Name == "Census Map") {
       census_map = map_pane.MapView.Map;
       break;
     }
   }
   if (census_map == null) {
     //Early exit, MessageBox, etc.
   }
   await QueuedTask.Run(() => {
     //Create the layout
     //Export, etc.
   };
   ...

 

 

estz2
by
New Contributor II

@CharlesMacleod Thank you for the effort you put into this solution, I really appreciate it! That was the problem.

0 Kudos