I want to create a new Layout programatically in ArcGIS Pro SDK. How to do that?

1095
4
10-29-2017 11:52 PM
SuryakantUpadhayay
New Contributor II

How to programatically create a new Layout, Open Layout Pane and Switch to Layout View in ArcGIS Pro SDK? 

Tags (2)
0 Kudos
4 Replies
JeffBarrette
Esri Regular Contributor

The creation of layouts and layout elements is coming at 2.1.  Currently you can only reference existing layouts.

Here is a snippet to create a new, simple layout:

//Create a new layout project item layout in the projectLayout newLayout = await QueuedTask.Run<Layout>(() => {   newLayout = LayoutFactory.Instance.CreateLayout(8.5, 11, LinearUnit.Inches);   newLayout.SetName("New 8.5x11 Layout");   return newLayout; });//Open new layout on the GUI threadProApp.Panes.CreateLayoutPane(newLayout);

Another example on managing layout views

//A layout view may exist but it may not be active//Iterate through each pane in the application and check to see if the layout is already open and if so, activate itforeach (var pane in ProApp.Panes) {   var layoutPane = pane as ILayoutPane;   if (layoutPane == null//if not a layout view, continue to the next pane    continue;   if (layoutPane.LayoutView.Layout == lyt) //if there is a match, activate the view  {     (layoutPane as Pane).Activate();     return;   } }

There will be many more layout pro snippets addressing these new capabilities when 2.1 is released.

Jeff

SuryakantUpadhayay
New Contributor II

Hi Jeff,

Finally, I found a way to open new Layout Programatically in 2.0 SDK too.

var wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_projectContainer_NewLayout");
var wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);

Once the Layout is opened 

LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();

Then we can do whatever we want to on the Layout.

0 Kudos
JeffBarrette
Esri Regular Contributor

Hello Suryakant,

I'm really glad you found a work-around for what you need at 2.0 but I'm curious if it really solves the issue.  It looks like you found a way to execute the existing New Layout command but how are you adding new elements to it?  At 2.1, not only will you be able to create layouts, open them in panes, but you will be able to create all layout element types.  Have you found a way to do that too?

Jeff

0 Kudos
SuryakantUpadhayay
New Contributor II

Hi Jeff, 

Yes, it solved my purpose. Though I had to do some tricks and workarounds.

So, I added 3 elements programatically after I created new Layout as described above. Those elements were MapFrame, North Arrow and Scale Bar. But, I believe similar thing can be done for other elements too.

To create a Map Frame I used following : 

wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newMapFrameButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);

Then to set its property or zoom level:

LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();
if (layoutItem != null)
{
      await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
     {
              Layout layout = layoutItem.GetLayout();
             if (layout == null)
                   return;


             MapFrame mf = layout.Elements.FirstOrDefault(item => item.Name.Equals("Map Frame")) as MapFrame;
             while (mf == null) //actually in large projects Loading map frames takes some time so this is just waiting for it to happen
             {
                   Task.Delay(TimeSpan.FromSeconds(1));
                    mf = layout.Elements.FirstOrDefault(item => item.Name.Equals("Map Frame")) as MapFrame;
               }

             mf.SetCamera(camera); //camera is where ever I want to focus/zoom

      });

}

For Scale Bar:

await Task.Delay(TimeSpan.FromSeconds(6));
wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newScaleBarButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);

For North Arrow:

wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newNorthArrowButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);

In the same manner as for MapFrame :

NorthArrow northArrow = layout.Elements.FirstOrDefault(item => item.Name.Equals("North Arrow")) as NorthArrow;
ScaleBar scaleBar = layout.Elements.FirstOrDefault(item => item.Name.Equals("Scale Bar")) as ScaleBar;

Once I got these objects I played with it and set what  wanted.

Roughly, my test code looks like following as a whole. Its not optimized and organized yet as it was just for testing but yes it works.

Camera camera = MapView.Active.Camera;
int count = ArcGIS.Desktop.Framework.FrameworkApplication.Panes.Find("esri_layouts_layoutPane").Count;
var wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_projectContainer_NewLayout");
var wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);

while (ArcGIS.Desktop.Framework.FrameworkApplication.Panes.Find("esri_layouts_layoutPane").Count == count)
{
await Task.Delay(TimeSpan.FromSeconds(3));
}

wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newMapFrameButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);
await Task.Delay(TimeSpan.FromSeconds(1));

LayoutProjectItem layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();
if (layoutItem != null)
{
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout == null)
return;

// Reference a mapframe by name
MapFrame mf = layout.Elements.FirstOrDefault(item => item.Name.Equals("Map Frame")) as MapFrame;
while (mf == null)
{
Task.Delay(TimeSpan.FromSeconds(1));
mf = layout.Elements.FirstOrDefault(item => item.Name.Equals("Map Frame")) as MapFrame;
}

mf.SetCamera(camera);

});
}

await Task.Delay(TimeSpan.FromSeconds(6));
wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newScaleBarButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);
layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();


await Task.Delay(TimeSpan.FromSeconds(6));
wrapper = FrameworkApplication.GetPlugInWrapper("esri_layouts_newNorthArrowButton");
wcommand = wrapper as ICommand;
if (wcommand == null)
return;

if (wcommand.CanExecute(null))
wcommand.Execute(null);
await Task.Delay(TimeSpan.FromSeconds(6));
layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
while (layoutItem.GetLayout().Elements.Count() != 3)
{
Task.Delay(TimeSpan.FromSeconds(1));
layoutItem = Project.Current.GetItems<LayoutProjectItem>().LastOrDefault<LayoutProjectItem>();
}
});

await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
// Reference and load the layout associated with the layout item
Layout layout = layoutItem.GetLayout();
if (layout == null)
return;

// Reference a mapframe by name
NorthArrow northArrow = layout.Elements.FirstOrDefault(item => item.Name.Equals("North Arrow")) as NorthArrow;
ScaleBar scaleBar = layout.Elements.FirstOrDefault(item => item.Name.Equals("Scale Bar")) as ScaleBar;

northArrow.IsVisible = true;
northArrow.SetWidth(5);
northArrow.SetX(northArrow.GetX() - 1.30);
northArrow.SetY(northArrow.GetY() + 1.70);

scaleBar.IsVisible = true;
scaleBar.SetWidth(5);
scaleBar.SetX(scaleBar.GetX() + 1.30);
scaleBar.SetY(scaleBar.GetY() + 2);

});

 

Regards,

Surya

0 Kudos