[Collection].RemoveAt(index)


Hoje recebi um email de um colega que me solicitava uma ajuda com relação ao controle CheckBoxList, onde ele tem um CheckBoxList no seu WebForm que carrega com alguns items. No evento Click de um Button qualquer, ele deveria excluir os items que foram marcados do CheckBoxList.

Pois bem, ele me mostrou o código que ele estava utilizando para isso, no evento Click de um Button:

        For i As Integer = 0 To Me.CheckBoxList1.Items.Count – 1
            If Me.CheckBoxList1.Items.Item(i).Selected Then
                Me.CheckBoxList1.Items.RemoveAt(i)
            End If
        Next

Mas isso atira uma Exception, do tipo: “Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index” caso você marque um item do CheckBoxList que não seja o último, e tem mesmo que ser apenas um, o que perde um pouco o sentido, já que a idéia de utilizar um CheckBoxList é permitir a múltipla escolha.

E se analisarmos o código que conseguimos ao fazer o disassembler, através do Reflector, da propriedade Items do CheckBoxList (que internamente é retornado um ListItemCollection (que encapsula um ArrayList)), mais precisamente do método RemoveAt, temos o seguinte código:

        Public Overridable Sub RemoveAt(ByVal index As Integer)
                If ((index < 0) OrElse (index >= Me._size)) Then
                        Throw New ArgumentOutOfRangeException(“index”, Environment.GetResourceString(“ArgumentOutOfRange_Index”))
                End If
                Me._size -= 1
                If (index < Me._size) Then
                        Array.Copy(Me._items, CType((index + 1), Integer), Me._items, index, CType((Me._size – index), Integer))
                End If
                Me._items(Me._size) = Nothing
                Me._version += 1
        End Sub

Como vemos, ele remove o elemento especificado no index e reconstrói o Array, através do método Array.Copy(…). Mas a Exception não “explode” ai e sim, quando a próxima iteração do laço For … Next for chamada, quando tentamos resgatar o próximo Item do ArrayList, item qual já não existirá mais, e vemos exatamente neste método a Exception que é atirada:

        Public Overridable Function get_Item(ByVal index As Integer) As Object
                If ((index < 0) OrElse (index >= Me._size)) Then
                Throw New ArgumentOutOfRangeException(“index”, Environment.GetResourceString(“ArgumentOutOfRange_Index”))
                End If
                Return Me._items(index)
        End Function

Mas e como fazemos para resolver este problema? Pois bem, a solução é lá bem simples, bastando apenas mudar a ordem do laço For … Next, ou seja, ao invés de percorrer a coleção de items do CheckBoxList de 0 até o número total de Items (ascendente), faz ao contrário, descrecendo (em 1) do número total de Items até 0. Ajustando o código acima (aquele da exclusão de items), fica conforme o código mostrado baixo:

        For i As Integer = Me.CheckBoxList1.Items.Count – 1 To 0 Step -1
            If Me.CheckBoxList1.Items.Item(i).Selected Then
                Me.CheckBoxList1.Items.RemoveAt(i)
            End If
        Next

Agora, o index nunca vai ser maior ou igual ao tamanho do ArrayList. Vale lembrar que isso não é válido somente para o CheckBoxList, mas sim todas as classes que implementam a interface IList.

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s