The grid.GridBoundColumnsCollection is only populated if you have explicitly added GridBoundColumns. If you have not added GridBoundColumns, then you always use the grid.Binder.InternalColumns collection, which should not be empty after its datasource has been set.
Instead of
Dim i As Int16 = gdItems.GridBoundColumns.IndexOf(Me.gdItems.Binder.InternalColumns("ItemID"))
If gdItems.CurrentCell.ColIndex = i Then
MsgBox("Can''''t Edit this cell")
e.Cancel = True
End If
try
Dim i As Int16 = gdItems.Binder.NameToColIndex("ItemID")
If gdItems.CurrentCell.ColIndex = i Then
MsgBox("Can''''t Edit this cell")
e.Cancel = True
End If
Another options is to just set gdItems.Binder.InternalColumns("ItemID").StyleInfo.ReadOnly = True in Form.Load. If you never want a cell in the column to become teh currentcell, you can also set ").StyleInfo.Enabled = False. Or, you could set ").StyleInfo.CellType = "Static". This way you could do things by setting a property instead of handling an event.