Remove item from ArrayList in a FOR loop (VB.NET)

Today I was trying to loop through an ArrayList (AL) that I had saved as a User Setting and remove values from the related AL that matched a specific value.  However, I was receiving the error, “Collection was modified; enumeration operation may not execute.”  This was because I was trying to remove an item from the AL while iterating through a For Each statement.

For Each str_env As String In My.Settings.Env_Collection

Dim env As Environment = GlobalVar.EnvCollection.ConvertStringToEnvironment(str_env)

If env.Division = div Then

My.Settings.Env_Collection.RemoveAt(i)

End If

i += 1

Next

To get around this, I tried switching over to a For statement instead, but received an Index Out of Bounds error because I used the original AL.Count() as my “stopping” point for the loop.  However, once I started removing items from the ArrayList, the Count() was less and there was no way to force my For loop to acknowledge that.  For example, if my initial Count() was 10 and I was removing 4 items, the For loop would continue up to 10 and not take into account any removed indexes; eventually, it would try to access an index that no longer existed in the ArrayList.

For i = 0 To My.Settings.Env_Collection.Count Step 1
Dim env As Environment = GlobalVar.EnvCollection.ConvertStringToEnvironment(My.Settings.Env_Collection(i))
If env.Division = div Then
My.Settings.Env_Collection.RemoveAt(i)
End If
Next

To resolve, simply step backwards through the array!

For i = (My.Settings.Env_Collection.Count – 1) To 0 Step1

Dim env As Environment = GlobalVar.EnvCollection.ConvertStringToEnvironment(My.Settings.Env_Collection(i))

If env.Division = div Then

My.Settings.Env_Collection.Remove(My.Settings.Env_Collection(i))

End If

Next

Simple, yet effective!  Happy coding!

Password Mask an unbound TextBox column in a DataGridView (VB.NET)

If you have ever wanted to mask the contents in a TextBox column on a DataGridView (DGV) control, you will notice that there is no pre-defined “password” format that you can apply.  I have gotten around this by setting the DataPropertyName attribute of the column and then checking the related property in the CellFormatting event.  It’s actually pretty simple and doesn’t involve very much coding at all!

DataPropertyName = "password"

DataPropertyName = "password"

After you have set the DataPropertyName for the related column(s) in your DGV, you need to add code that will evaluate this property when the data is loaded.  For this, I will use the CellFormatting event.

Before we begin, I want to set the character that will be displayed instead of actual value.  For this, I will use an asterisk (*).

Private pwd As Char = “*”

In the below example, my DataGridView is named dg_Divisions.  This routine will store the value of any field with the DataPropertyName of “password” into the related cell’s Tag property and will change each character in the Value to an asterisk.  If the field is not a “password” field, it will set the Tag to Nothing (null).

Private Sub dgv_PwdFormatting(ByVal sender As Object, ByVal e As DataGridViewCellFormattingEventArgs) Handles dg_Divisions.CellFormatting
If dg_Divisions.Columns(e.ColumnIndex).DataPropertyName = “passwordAnd e.Value <> Nothing Then
dg_Divisions.Rows(e.RowIndex).Tag = e.Value
e.Value = New String(pwd, e.Value.ToString.Length)
Else
dg_Divisions.Rows(e.RowIndex).Tag = Nothing
End If
End Sub
After the Tags and Values have been changed, we want the user to be able to see and modify the value if they begin editing the cell.  To do this, I will use the EditingControlShowing event.
Private Sub dgv_PwdEditing(ByVal sender As Object, ByVal e As DataGridViewEditingControlShowingEventArgs) Handles dg_Divisions.EditingControlShowing
If (dg_Divisions.CurrentRow.Tag <> Nothing) Then
e.Control.Text = dg_Divisions.CurrentRow.Tag.ToString()
End If
End Sub
Value displayed as asterisks

Value displayed as asterisks

Editing the cell displays the underlying contents

Editing the cell displays the underlying contents

That’s all there is to it!  Happy coding!

Move an unbound DataGridView row up or down via code (VB.NET)

Doing something as simple as moving an unbound DataGridView (dgv) row up or down via code really shouldn’t be as difficult of a task as Visual Studio makes it.

I started out by creating two buttons on a Windows Form called btn_Up and btn_Down, respectively.  I then created a single sub routine that would be passed in the number of rows (+1 or -1) that the current row should be moved.  For example, to move a row “up” in dgv, it’s row index will be one less than it currently is (before the move)

Private Sub btn_Up_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Up.Click

        ‘If already on the first row, don’t try to move the row up

        If Me.dgv_FinishingScheduleColumns.CurrentCell.RowIndex = 0 Then

            Exit Sub

        End If

MoveRow(-1) ‘ move up in the datagridview (row index is 1 less)

End Sub

Private Sub btn_Down_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Down.Click

‘If already on the bottom row, don’t try to move the row down

        If Me.dgv_FinishingScheduleColumns.CurrentCell.RowIndex = Me.dgv_FinishingScheduleColumns.RowCount – 1 Then

            Exit Sub

End If

MoveRow(1) ‘ move down in the datagridview (row index is 1 more)

End Sub

Private Sub MoveRow(ByVal i As Integer)

Try

If (Me.dgv.SelectedCells.Count > 0) Then

Dim curr_index As Integer = Me.dgv.CurrentCell.RowIndex

Dim curr_col_index As Integer = Me.dgv.CurrentCell.ColumnIndex

Dim curr_row As DataGridViewRow = Me.dgv.CurrentRow

Me.dgv.Rows.Remove(curr_row)

Me.dgv.Rows.Insert(curr_index + i, curr_row)

Me.dgv.CurrentCell = Me.dgv(curr_col_index , curr_index + i)

End If

Catch ex As Exception

‘ do nothing if error encountered while trying to move the row up or down

End Try

End Sub

In addition to moving the row that contains the selected cell up or down, the MoveRow sub routine also selects the related cell in its “new” location after it has been moved.  I kept trying to set the CurrentCell.Selected value, but in the end, I needed to actually specify what the CurrentCell actually was.

Happy programming!

Private Sub btn_Up_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Up.Click
MoveRow(-1) ‘ move up in the datagridview (row index is 1 less)
End Sub
Private Sub btn_Down_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_Down.Click
MoveRow(1) ‘ move down in the datagridview (row index is 1 more)
End Sub
Private Sub MoveRow(ByVal i As Integer)
Try
If (Me.dg_Environments.SelectedCells.Count > 0) Then
Dim curr_index As Integer = Me.dg_Environments.CurrentCell.RowIndex
Dim curr_cell_index As Integer = Me.dg_Environments.CurrentCell.ColumnIndex
Dim curr_row As DataGridViewRow = Me.dg_Environments.CurrentRow
Me.dg_Environments.Rows.Remove(curr_row)
Me.dg_Environments.Rows.Insert(curr_index + i, curr_row)
Me.dg_Environments.CurrentCell = Me.dg_Environments(curr_cell_index, curr_index + i)
End If
Catch ex As Exception
‘ do nothing if error encountered while trying to move the row up or down
End Try
End Sub