Nested Legend -

2681
10
Jump to solution
07-20-2012 05:14 AM
LakshmananVenkatesan
Occasional Contributor II
Hello
I have a map document which has nested groups like below and published as dynamic service layer

Layers
   Group A
     A.1
     A.2
     A.3
   Group B
     B.1
     B.2
   Layer C
   Layer D
   Group E
       Group E1
          E1.1
          E1.2
       Group E2
         E2.1
         E2.2
   Layer F

using sliverlight API , I want to do below  actions
a) remove layers B.2 , Layer D, E1.2, E2.2     
b) Based on user preferences - set these layers to visible E1.1 , E2.1, Layer C,
c) All other available layerrs set to invisible

I have just provided a layers names which needs to be removed and make visible/invisible. How to acheive this?. Bascically am
looking for recursive loop kind of logic to make all these changes and display in legend. Please give me an psuedo code.
0 Kudos
1 Solution

Accepted Solutions
DominiqueBroux
Esri Frequent Contributor
A.2 layer is visble in map. But A.2 has been removed successfully on legend refreshed event


Removing a layerItem from the legend doesn't change anything for the layer or sublayer visibility in the map.

You have to do it by code at the same time you remove the layerItem.
Something like:
foreach (var pair in toDeletes) {     var parentLayerItem = pair.Item1;     var layerItemToDelete = pair.Item2;      parentLayerItem.LayerItems.Remove(layerItemToDelete);      Layer layer = parentLayerItem.Layer;     int subID = layerItemToDelete.SubLayerID;     if (layer is ISublayerVisibilitySupport && subID > 0)*         (layer as ISublayerVisibilitySupport).SetLayerVisibility(subID, false);     parentLayerItem.Layer.SetSublayerViisbility(layerItemToDelete.SublayerId, false); }

View solution in original post

0 Kudos
10 Replies
JonathanHouck
New Contributor III
I'm doing this in one of my apps right now, I've got a big dynamicmapservicelayer and I'm removing several layers and group layers so I only display pertinent data.  Here's how I did it, but I'm sure someone more savvy could have a better way:

private void Legend_Refreshed(object sender, Legend.RefreshedEventArgs e)
        {
            List<LayerItemViewModel> removeLayerItemVM = new List<LayerItemViewModel>();
            List<LayerItemViewModel> removeLayerItemVM2 = new List<LayerItemViewModel>();
            List<string> removeLayers = new List<string>();
            removeLayers.Add("Service Agreement Areas");
            removeLayers.Add("HTE Routes");
            removeLayers.Add("Water 3-way");
            removeLayers.Add("Water 4-way");
            removeLayers.Add("Water 5-way");
            removeLayers.Add("Water 6-way");
            
            
            if (e.LayerItem.LayerItems != null)
            {
                foreach (LayerItemViewModel layerItemVM in e.LayerItem.LayerItems)
                {
                    //removes the feature layers in the water group layer from the legend:
                    foreach (LayerItemViewModel livm in layerItemVM.LayerItems)
                    {
                        foreach (string rlayer in removeLayers)
                        {
                            if (livm.Label == rlayer)
                                removeLayerItemVM2.Add(livm);
                        }
                    }

                    foreach (LayerItemViewModel rlivm in removeLayerItemVM2)
                    {
                        layerItemVM.LayerItems.Remove(rlivm);
                    }

                    //collapses all the legend items:
                    if (layerItemVM.IsExpanded == true)
                    {
                        layerItemVM.IsExpanded = false;

                        for (int i = 0; i < layerItemVM.LayerItems.Count; i++)
                        {
                            layerItemVM.LayerItems.IsExpanded = false;
                        }
                    }
                    //removes all the other group layers from the legend:
                    if (layerItemVM.Label == "General Layers")
                        removeLayerItemVM.Add(layerItemVM);

                    else if (layerItemVM.Label == "Storm Layers")
                        removeLayerItemVM.Add(layerItemVM);

                    else if (layerItemVM.Label == "Sewer Layers")
                        removeLayerItemVM.Add(layerItemVM);
                }

                foreach (LayerItemViewModel remLayerItemVM in removeLayerItemVM)
                {
                    e.LayerItem.LayerItems.Remove(remLayerItemVM);
                }
            }
            
            else
            {
                e.LayerItem.IsExpanded = false;
            }
        }


Basically I create a few different lists of layers I want removed, append layers to the lists, and then remove the lists.  It got a little tricky with the first nested foreach because I had to break into the layer item view model's layeritems and only remove the layers I defined in the list above.  Just for context, the above code removes my general, sewer, and storm items from the legend, and leaves all the water layers except those I added to the removeLayers list.
0 Kudos
LakshmananVenkatesan
Occasional Contributor II
Thanks. But am looking for an elegant solution which handles any kind of nested struture in map document. Basically I look for recursive loop logic to handle the case. I have seen another thread where dbroux provided sample for getting selecetd items but that does not help me.

My requirement is based on user preference any layer can be removed at run time and any layers can set to visible/invisble based on preference. How to achieve this? . Any one can help on this???
0 Kudos
DominiqueBroux
Esri Frequent Contributor
Basically I look for recursive loop logic to handle the case. I have seen another thread where dbroux provided sample for getting selecetd items but that does not help me.


You can reuse the same idea as for the selected items, i.e write a recursive extension method returning all layer items and then filter with the criteria you need (selected is just a particular case).

For removing the additional difficulty is that you need the parent item as well in order to be able to call parent.LayerItems.Remove(layerItemToRemove);

So you can tweak the extension method to return an enumeration of pair <Parent, Child> (using .net Tuple but you might create your own class).

public static class LegendExtensions{
    // Go recursively through the LayerItems and return a tuple <parent, child> for each child
   public static IEnumerable<Tuple<LayerItemViewModel, LayerItemViewModel>> GetAllParentChild(this LayerItemViewModel layerItem)
    {
        return layerItem == null || layerItem.LayerItems == null ?
            Enumerable.Empty<Tuple<LayerItemViewModel, LayerItemViewModel>>() :
            layerItem.LayerItems.SelectMany(child => new[] { new Tuple<LayerItemViewModel, LayerItemViewModel>(layerItem, child) }.Concat(GetAllParentChild(child)));
    }
}


Then you can use that extension method to delete the items you want with code like:

var toDeletes = LayerItem.GetAllParentChild().Where(pair =>  new[] {"Service Agreement Areas", "HTE Routes", ....}.Contains(pair.Item2.Label)).ToArray();
foreach (var pair in toDeletes)
    pair.Item1.LayerItems.Remove(pair.Item2);
0 Kudos
LakshmananVenkatesan
Occasional Contributor II
dbroux ,

Thank you. I could able to get tuple pair of parent,child which I need to delete. But I do not understand second part, can you please explain in simple terms?.
0 Kudos
DominiqueBroux
Esri Frequent Contributor
dbroux ,

Thank you. I could able to get tuple pair of parent,child which I need to delete. But I do not understand second part, can you please explain in simple terms?.


Second part might be confusing due to the usage of Tuple and it's members Item1 and Item2.
Item1 is the parent, Item2 is the child to delete.

Likely clearer by using intermediate variables:

foreach (var pair in toDeletes)
{
    var parentLayerItem = pair.Item1;
    var layerItemToDelete = pair.Item2;

    parentLayerItem.LayerItems.Remove(layerItemToDelete);
}

(it's why it could make sense to create your own class with better names than Tuple).
0 Kudos
LakshmananVenkatesan
Occasional Contributor II
Broux,

Thanks again. But in below code under legend refresh method, tupleParentChild has value pairs but looping does not happens?.
I guess am doing something wrong here.. sorry to bother you please help me on this.




IEnumerable<Tuple<LayerItemViewModel, LayerItemViewModel>> tupleParentChild;  // declaration 


if (e.LayerItem.LayerItems != null)
            {
                foreach (LayerItemViewModel layerItemVM in e.LayerItem.LayerItems)
                {

                    if (layerItemVM.IsGroupLayer)
                    {
                        composites.Add(layerItemVM);
                        while (composites.Count > 0)
                        {
                            LayerItemViewModel layerItemVMGroup = composites[0];

                            foreach (LayerItemViewModel innerLayerItems in layerItemVMGroup.LayerItems)
                            {
                                if (innerLayerItems.IsGroupLayer == false)
                                {
                                    innerLayerItems.IsExpanded = true;
                                  // Requirement : If strVisibleArray3D does not contains then remove the layer from Legend
                                    if (!strVisibleArray3D.Contains(innerLayerItems.Label))
                                    {
                                       
      // dbroux method to get the parent child using legend extension method 
   tupleParentChild = LegendExtension.GetAllParentChild(innerLayerItems);

      // issue always tupleParentChild has a pair of values but looping does not taking place
                                        foreach (var pair in tupleParentChild.ToArray())
                                        {
                                            var parentLayerItem = pair.Item1;
                                            var layerItemToDelete = pair.Item2;

                                            parentLayerItem.LayerItems.Remove(layerItemToDelete);
                                        }

                                    }
                                    else
                                    {
                                        if (strPrefLayers.Contains(innerLayerItems.Label))
                                        {
                                            innerLayerItems.IsEnabled = true;
                                            innerLayerItems.IsSelected = true;
                                        }
                                    }

                                }
                                else
                                {
                                    composites.Add(innerLayerItems);
                                }
                            }


                            composites.Remove(layerItemVMGroup);
                        }
                    }
                    else
                    {
                        if (!strVisibleArray3D.Contains(layerItemVM.Label))
                        {
                            // remove the layer 
                        }
                        else
                        {
                            if (strPrefLayers.Contains(layerItemVM.Label))
                            {
                                layerItemVM.IsEnabled = true;
                                layerItemVM.IsSelected = true;
                            }
                        }
                    }
                }

               
                

0 Kudos
DominiqueBroux
Esri Frequent Contributor
In my mind it's to use as shown below, but I may have missed somthing in your need.

private void Legend_Refreshed(object sender, Legend.RefreshedEventArgs e)
{
    List<string> removeLayers = new List<string>
    {
        "Service Agreement Areas",
        "HTE Routes",
        "Water 3-way",
        "Water 4-way",
        "Water 5-way",
    };

   var toDeletes = LayerItem.GetAllParentChild().Where(pair =>  removeLayers.Contains(pair.Item2.Label)).ToArray();
   foreach (var pair in toDeletes)
        pair.Item1.LayerItems.Remove(pair.Item2);
}
0 Kudos
LakshmananVenkatesan
Occasional Contributor II
dbroux,

Thanks. Finally I have managed to remove the layer items. Now, am facing new issue i.e.After removing A.2 from the Group A
when I check (i.e select) "Group A " A.2 layer is visble in map. But A.2 has been removed successfully on legend refreshed event but while selecting Group A the layer A.2 is appearing in the map. I dont know reason for this case?. Can you throw some light on this ?.

Layers
Group A
A.1
A.2
A.3
0 Kudos
LakshmananVenkatesan
Occasional Contributor II
repost and brough forward
0 Kudos