C# ArcGIS Pro SDK, Move layer B in Contents beneath layer A

2030
4
Jump to solution
09-06-2019 11:43 AM
MikeRatcliffe
Occasional Contributor

If i can get the current index of layer A, I think I add one to the int to move layer B directly beneath it.

I need to get layer A's index in the Contents pane.

Help is appreciated.

0 Kudos
1 Solution

Accepted Solutions
UmaHarano
Esri Regular Contributor

Hi Mike

Here is some code snippet that recursively checks through all the layers (including group layers) to move the layer.

In this example the layer I want to move is the "US Cities layer". I want to move this layer to be below US Counties layer.

Thanks

Uma

        protected override void OnClick()
        {
            var layerToMove = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().Where(f => f.Name == "U.S. Cities").FirstOrDefault();
            if (layerToMove == null)
            {
                MessageBox.Show("Layer U.S. Cities not found ");
                return;
            }
            var moveBelowThisLayerName = "U.S. Counties (Generalized)";
            //In order to move layerToMove, I need to know if the destination is a group layer and the zero based position it needs to move to.
            Tuple<GroupLayer, int> moveToLayerPosition = FindLayerPosition(null, moveBelowThisLayerName);
            if (moveToLayerPosition.Item2 == -1) {
                MessageBox.Show($"Layer {moveBelowThisLayerName} not found ");
                return;
            }
            QueuedTask.Run( () => {
                if (moveToLayerPosition.Item1 != null) //layer gets moved into the group
                    moveToLayerPosition.Item1.MoveLayer(layerToMove, moveToLayerPosition.Item2);
                else //Layer gets moved into the root
                    MapView.Active.Map.MoveLayer(layerToMove, moveToLayerPosition.Item2);
            });            
        }

        private Tuple<GroupLayer, int> FindLayerPosition(GroupLayer groupLayer, string moveToLayerNameBelow)
        {
            int index = 0;
            foreach (var lyr in groupLayer != null? groupLayer.Layers : MapView.Active.Map.Layers)
            {
                index++;
                if (lyr is GroupLayer)
                {
                    //We descend into a group layer and search all the layers within.
                    var result = FindLayerPosition(lyr as GroupLayer, moveToLayerNameBelow);
                    if (result.Item2 >= 0)
                        return result;
                    continue;
                }
                if (moveToLayerNameBelow == lyr.Name)    //We have a match
                {
                    return new Tuple<GroupLayer, int>(groupLayer, index);
                }                           
            }
            return new Tuple<GroupLayer, int>(null, -1);
        }

View solution in original post

4 Replies
UmaHarano
Esri Regular Contributor

Hi Mike

One way to do this is -

  • Get the "Layers" collection from the Map using the Layers property. This will give you the collection of layers in that map
  • You can then iterate through this to get the layer you want to move your layer next to. (Using the MoveLayer method )
  • Things to note: You have to check if the layer is a "Group Layer" in the collection of Layers returned.  If it is a Group Layer, you have to iterate through this collection. Index of the layer is relative to the parent. So within the Group Layer, the index will be relative to the parent group.

Thanks

Uma

MikeRatcliffe
Occasional Contributor

Well,

GVar.index = 0;
FeatureLayer layer_A = map.FindLayers(lyrname).OfType<FeatureLayer>().FirstOrDefault() as FeatureLayer;

GroupLayer grp = map.FindLayers(grplyrname).OfType<GroupLayer>().FirstOrDefault() as GroupLayer;

int g = grp.Layers.IndexOf(layer_A);  //when IN GroupLayer grp
int m = map.Layers.IndexOf(layer_A);  //when merely in the active map

if (g == -1)     //g will return -1 as the index if it isn't inside the GroupLayer grp
{
   GVar.index = m;      //sets the index value of layer_A from the map
}
else
{
   GVar.index = g;      //otherwise sets the index value of layer_A from the GroupLayer grp
}

int cci = GVar.index + 1;   //will be the index placment of Layer_B

FeatureLayer layer_B = map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name == "layer_B_name");

if (g == -1)
{
   map.MoveLayer(layer_B, cci);
}
else
{
   grp.MoveLayer(layer_B, cci);
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

This is good enough for now.  However, If the user moves layer_A inside a group layer different from that specified, its index will default to -1 and place layer_B relative to its placement in the active map and not to the unspecified group layer.   Further investigating Layer.Parent to identify the unspecified group layer in this scenario.

Thanks, Uma.

0 Kudos
UmaHarano
Esri Regular Contributor

Hi Mike

Here is some code snippet that recursively checks through all the layers (including group layers) to move the layer.

In this example the layer I want to move is the "US Cities layer". I want to move this layer to be below US Counties layer.

Thanks

Uma

        protected override void OnClick()
        {
            var layerToMove = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().Where(f => f.Name == "U.S. Cities").FirstOrDefault();
            if (layerToMove == null)
            {
                MessageBox.Show("Layer U.S. Cities not found ");
                return;
            }
            var moveBelowThisLayerName = "U.S. Counties (Generalized)";
            //In order to move layerToMove, I need to know if the destination is a group layer and the zero based position it needs to move to.
            Tuple<GroupLayer, int> moveToLayerPosition = FindLayerPosition(null, moveBelowThisLayerName);
            if (moveToLayerPosition.Item2 == -1) {
                MessageBox.Show($"Layer {moveBelowThisLayerName} not found ");
                return;
            }
            QueuedTask.Run( () => {
                if (moveToLayerPosition.Item1 != null) //layer gets moved into the group
                    moveToLayerPosition.Item1.MoveLayer(layerToMove, moveToLayerPosition.Item2);
                else //Layer gets moved into the root
                    MapView.Active.Map.MoveLayer(layerToMove, moveToLayerPosition.Item2);
            });            
        }

        private Tuple<GroupLayer, int> FindLayerPosition(GroupLayer groupLayer, string moveToLayerNameBelow)
        {
            int index = 0;
            foreach (var lyr in groupLayer != null? groupLayer.Layers : MapView.Active.Map.Layers)
            {
                index++;
                if (lyr is GroupLayer)
                {
                    //We descend into a group layer and search all the layers within.
                    var result = FindLayerPosition(lyr as GroupLayer, moveToLayerNameBelow);
                    if (result.Item2 >= 0)
                        return result;
                    continue;
                }
                if (moveToLayerNameBelow == lyr.Name)    //We have a match
                {
                    return new Tuple<GroupLayer, int>(groupLayer, index);
                }                           
            }
            return new Tuple<GroupLayer, int>(null, -1);
        }
MikeRatcliffe
Occasional Contributor

Uma,

I'm feeling pretty good about this approach.  I was able to implement your footprint into my add-in tool.

I really appreciate your help.

private Tuple<GroupLayer, int> GetLyr_Loc(GroupLayer grplyr, string movebelowlayername)
        {
            Map map = MapView.Active.Map;       //solution footprint provided by Uma Harano, esristaff 2019
            int index = 0;
            foreach (var lyr in grplyr != null ? grplyr.Layers : map.Layers)
            {
                index++;
                if (lyr is GroupLayer)
                {
                    //We descend into a group layer and search all the layers within.
                    Tuple<GroupLayer, int> result = GetLyr_Loc(lyr as GroupLayer, movebelowlayername);
                    if (result.Item2 >= 0)
                        return result;
                    continue;
                }
                if (movebelowlayername == lyr.Name)    //We have a match
                {
                    return new Tuple<GroupLayer, int>(grplyr, index);
                }
            }
            return new Tuple<GroupLayer, int>(null, -1);
        }

private async void cctvlstbx_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            await ActMap();
            Map map = MapView.Active.Map;
            MapView MV = MapView.Active;
            string lyrname = "Sewer File Geodatabase";
            string sublyrname = "Sewer Mains";                                                      //Check for Sewer Mains in TOC
            string url = GVar.DL + @"gisdata\layers\" + lyrname + ".lyr";
            Uri uri = new Uri(url);

            string cctvguide = "ccTV Guide";
            string url2 = GVar.DL + @"gisdata\layers\" + cctvguide + ".lyr";
            Uri uri2 = new Uri(url2);

            FeatureLayer lyrcheck3 = map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name == sublyrname);
            
            if (lyrcheck3 == null)
            {
                await QueuedTask.Run(() => LayerFactory.Instance.CreateFeatureLayer(uri, map));
            }

            FeatureLayer ssmain_lyr = map.FindLayers(sublyrname).OfType<FeatureLayer>().FirstOrDefault() as FeatureLayer;

            if (ssmain_lyr.IsVisible == false)
            {
                await QueuedTask.Run(() =>
                {
                    ssmain_lyr.SetVisibility(true);
                });
            }

            FeatureLayer lyrchck = map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name == cctvguide);

            if (lyrchck == null)
            {
                if (GVar.cctvlyr == true)
                {
                    string message = "Would you like to add the ccTV Guide layer for reference?";
                    string caption = " Add ccTV Guide?";
                    MessageBoxButtons buttons = MessageBoxButtons.YesNo;
                    MessageBoxIcon icon = MessageBoxIcon.Exclamation;
                    MessageBoxDefaultButton defbutton = MessageBoxDefaultButton.Button1;
                    MessageBoxOptions bxOpt = MessageBoxOptions.DefaultDesktopOnly;
                    DialogResult result;

                    result = MessageBox.Show(message, caption, buttons, icon, defbutton, bxOpt);

                    if (result == DialogResult.Yes)
                    {
                        await QueuedTask.Run(() => LayerFactory.Instance.CreateFeatureLayer(uri2, map));
                        await MV.RedrawAsync(true);
                    }
                    if (result == DialogResult.No)
                    {
                        GVar.cctvlyr = false;
                    }
                };
            }

            FeatureLayer cctvlyr = map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(l => l.Name == cctvguide);

            if (cctvlyr != null)        //solution footprint provided by Uma Harano, esristaff 2019
            {
                //In order to move cctvlyr, I need to know if the destination is a group layer and the zero based position it needs to move to.
                Tuple<GroupLayer, int> MoveTo_Loc = GetLyr_Loc(null, sublyrname);
                await QueuedTask.Run(() =>
                {
                    if (MoveTo_Loc.Item1 == null) //layer gets moved into the root
                    {
                        map.MoveLayer(cctvlyr, MoveTo_Loc.Item2);
                    }
                    else //Layer gets moved into the group
                    {
                        GVar.containername = MoveTo_Loc.Item1.Name;
                        MoveTo_Loc.Item1.MoveLayer(cctvlyr, MoveTo_Loc.Item2);
                    }
                    if (cctvlyr.IsVisible == false)
                    {
                        cctvlyr.SetVisibility(true);
                    }
                });
            }

            GroupLayer sm_grp = map.FindLayers(GVar.containername).OfType<GroupLayer>().FirstOrDefault();

            if (sm_grp != null && sm_grp.IsVisible == false)
            {
                await QueuedTask.Run(() =>
                {
                    sm_grp.SetVisibility(true);
                });
            }

//further functions below...