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.