Help needed with recursion: delete all empty group layers

966
7
Jump to solution
08-26-2013 08:25 AM
deleted-user-VeC5jUIlNXtq
Occasional Contributor III
Hi all,

I will spare the details of why my map has several empty group layers unless anyone is interested, though it's not likely to be relevant at this point. We have a map of group layers with several more sets of nested group layers within (to keep similar datasets organized).

I'm trying to set something up to loop through the entire table of contents (say, 6 major group layers), check if a group layer is empty (i. e. contains no feature layers), if it is remove it, otherwise do nothing.

I'll post the code below, and the error I'm getting is "Value does not fall within the expected range" which I'm guessing means that the For loop is breaking (in: Public Sub recursiveSearch(ByVal pLayer As ILayer))
. My theory is that deleting the group layer takes the total count down by 1, thus having the for loop sitting at z = 2 when the pMap.LayerCount - 1 is only 1 now. But that's a working theory 😛

In the main part of the code:

        For z = 0 To pMap.LayerCount - 1             pLayerCheck = pMap.Layer(z)             Call recursiveSearch(pLayerCheck)         Next z


Basically, send each major group layer to the functions below. Any assistance is appreciated and please let me know if more info is required.

Thank you!

Public Sub deleteGroupLayer(ByVal pLayer As ILayer)         Dim pMxDoc As IMxDocument         Dim pMap As IMap         Dim pTempLayer As ICompositeLayer          pMxDoc = My.ArcMap.Document         pMap = pMxDoc.FocusMap          If TypeOf pLayer Is ICompositeLayer Then             pTempLayer = pLayer             If pTempLayer.Count = 0 Then                 pMap.DeleteLayer(pLayer)             End If         End If       End Sub      Public Sub recursiveSearch(ByVal pLayer As ILayer)          Dim bContinue As Boolean         bContinue = True          Dim iLayerCount As Integer         If Not TypeOf pLayer Is ICompositeLayer Then             Exit Sub         Else             Dim pCompLayer As ICompositeLayer             Dim pSubLayer As ILayer             pCompLayer = pLayer             iLayerCount = pCompLayer.Count             For SubLayerIndex = 0 To iLayerCount - 1                 pSubLayer = pCompLayer.Layer(SubLayerIndex)                 recursiveSearch(pSubLayer)                 Call deleteGroupLayer(pSubLayer)             Next SubLayerIndex         End If      End Sub
0 Kudos
1 Solution

Accepted Solutions
NeilClemmons
Regular Contributor III
There's another way to do this that doesn't require recursion.  Use IMap.Layers and pass in the id for IGroupLayer.  This will return an enumeration of all group layers in the TOC.  From there, just loop through and delete the ones that are empty.

The id for IGroupLayer is {EDAD6644-1810-11D1-86AE-0000F8751720}.

View solution in original post

0 Kudos
7 Replies
JeffMatson
Occasional Contributor III
Your theory is correct...Just reverse the order you are removing the layers and it should work fine:

For pMap.LayerCount - 1 To 0 



Hi all,

I will spare the details of why my map has several empty group layers unless anyone is interested, though it's not likely to be relevant at this point. We have a map of group layers with several more sets of nested group layers within (to keep similar datasets organized).

I'm trying to set something up to loop through the entire table of contents (say, 6 major group layers), check if a group layer is empty (i. e. contains no feature layers), if it is remove it, otherwise do nothing.

I'll post the code below, and the error I'm getting is "Value does not fall within the expected range" which I'm guessing means that the For loop is breaking (in: Public Sub recursiveSearch(ByVal pLayer As ILayer))
. My theory is that deleting the group layer takes the total count down by 1, thus having the for loop sitting at z = 2 when the pMap.LayerCount - 1 is only 1 now. But that's a working theory 😛

In the main part of the code:

        For z = 0 To pMap.LayerCount - 1
            pLayerCheck = pMap.Layer(z)
            Call recursiveSearch(pLayerCheck)
        Next z


Basically, send each major group layer to the functions below. Any assistance is appreciated and please let me know if more info is required.

Thank you!

Public Sub deleteGroupLayer(ByVal pLayer As ILayer)
        Dim pMxDoc As IMxDocument
        Dim pMap As IMap
        Dim pTempLayer As ICompositeLayer

        pMxDoc = My.ArcMap.Document
        pMap = pMxDoc.FocusMap

        If TypeOf pLayer Is ICompositeLayer Then
            pTempLayer = pLayer
            If pTempLayer.Count = 0 Then
                pMap.DeleteLayer(pLayer)
            End If
        End If


    End Sub

    Public Sub recursiveSearch(ByVal pLayer As ILayer)

        Dim bContinue As Boolean
        bContinue = True

        Dim iLayerCount As Integer
        If Not TypeOf pLayer Is ICompositeLayer Then
            Exit Sub
        Else
            Dim pCompLayer As ICompositeLayer
            Dim pSubLayer As ILayer
            pCompLayer = pLayer
            iLayerCount = pCompLayer.Count
            For SubLayerIndex = 0 To iLayerCount - 1
                pSubLayer = pCompLayer.Layer(SubLayerIndex)
                recursiveSearch(pSubLayer)
                Call deleteGroupLayer(pSubLayer)
            Next SubLayerIndex
        End If

    End Sub
0 Kudos
deleted-user-VeC5jUIlNXtq
Occasional Contributor III
Wow, how did I miss that simple switch. I'll give it a shot and let you know if that works.

Thanks for the suggestion 🙂

Edit: actually a thought occurs. I know for a fact that none of the 6 major group layers will ever be empty. So the "main part" of the code doesn't need changing, but something within the recursive does.

Your suggestion may still be the answer, but wouldn't it be:

            For SubLayerIndex = 0 To iLayerCount - 1
                pSubLayer = pCompLayer.Layer(SubLayerIndex)
                recursiveSearch(pSubLayer)
                Call deleteGroupLayer(pSubLayer)
            Next SubLayerIndex


that would need to be modified? I think that's where the error stems from.
0 Kudos
NeilClemmons
Regular Contributor III
There's another way to do this that doesn't require recursion.  Use IMap.Layers and pass in the id for IGroupLayer.  This will return an enumeration of all group layers in the TOC.  From there, just loop through and delete the ones that are empty.

The id for IGroupLayer is {EDAD6644-1810-11D1-86AE-0000F8751720}.
0 Kudos
deleted-user-VeC5jUIlNXtq
Occasional Contributor III
That sounds much simpler Neil thank you. I have often used your responses to other threads as answers to my own questions.

Curious though, IGroupLayer doesn't have a .count property which is what I'm using to check if it's empty or not, should I use ICompositeLayer instead? I'll have a look around, but the IMap.Layers page doesn't include ICompositeLayer GUID as a "common" interface.

Thanks for your help!
0 Kudos
NeilClemmons
Regular Contributor III
The enumeration will hold objects of type IGroupLayer.  You can then QI over to ICompositeLayer without any problem since a group layer is also a composite layer.  You should be able to use the id for ICompositeLayer if you want but you'll have to look it up in the system registry.
0 Kudos
deleted-user-VeC5jUIlNXtq
Occasional Contributor III
I spoke too soon, I was just about to say, I can probably QI to the ICompositeLayer.

I'll give that a shot and see how it goes, thanks again!
0 Kudos
deleted-user-VeC5jUIlNXtq
Occasional Contributor III
Awesome, it worked almost flawlessly. There are a couple empty group layers remaining, which is more than likely due to my sloppy code logic ( + 1 or - 1 somewhere).

I'll play around with it and hopefully that will be the end of this longer than planned nightmare.

Thanks to both of you for your suggestions, very much appreciated!
0 Kudos