DataGridView.Column(ColumnName as String) gives error "Object reference not set to an instance of an object"
This is something that has been bugging me for a while as it is easily fixed but not desirable.
I have a DataGridView that has 5 columns. The first is called ID.
In vb.net the following line gives an error 开发者_运维百科"Object reference not set to an instance of an object":
dgvJobs.Columns("ID").Visible = False ' ERROR
dgvJobs.Columns(0).Visible = False ' OK
Obviously using the name is much better than a hard coded value to reference the column but wondering if there is anything i can do to get this to work correctly?
The datagridview datasource is BindingSource control with the datasource being a dataset.
EDIT: Based on the answer I have created the following function that does exactly as I need:
Private Function GetColName(ByVal name As String, ByRef dgv As DataGridView) As Integer
Dim retVal As Integer
For Each col As DataGridViewColumn In dgv.Columns
If col.HeaderText = name Then
retVal = col.Index
Exit For
End If
Next
Return retVal
End Function
Useage:
dgvJobs.Columns(GetColName("ID", dgvJobs)).Visible = False
Two tips:
1- By default, the Winforms designer creates an object in your forms Class for every column that exists in a DataGridView. So if you have a column named MyIdColumn, for instance, you should be able to access the column in the form code like this:
Me.MyIdColumn.Visible = False
If you want to access an element of the DataGridView, you could do something like this:
Dim value = dgv.Item(MyIdColumn.Index, rowIndex).Value
Using this trick, if the column name changes, there's no problem because you reference the column directly instead of a string representing a column name that could change.
2- Your GetColName method could be better; I would transform it into an extension method:
<System.Runtime.CompilerServices.Extension()> _
Private Function GetColByHeaderText(ByVal dgv As DataGridView, ByVal name As String) As DataGridViewColumn
For Each col As DataGridViewColumn In dgv.Columns
If col.HeaderText = name Then
Return col
End If
Next
Return Nothing
End Function
Usage:
dgv.GetColByHeaderText("ID").Visible = False
A lot nicer IMO!
Perhaps the column is not called what you think it is?
Have you checked the Columns(0).Name property to verify?
It might have been called "tablename_ID" or something by the BindingSource
Public Class Form2 Private list As List(Of Person) Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load CreateDGV() PopulatingDGV()
End Sub
Private Sub CreateDGV()
dataGridView1.AllowUserToAddRows = False
dataGridView1.RowHeadersVisible = False
dataGridView1.Columns.Add("col1", "Column 1")
Dim column2 As DataGridViewComboBoxColumn = CreateComboBoxColumn1()
Dim column3 As DataGridViewComboBoxColumn = CreateComboBoxColumn2()
dataGridView1.Columns.Add(column2)
dataGridView1.Columns.Add(column3)
'adding an event:
'DataGridView1.EditingControlShowing += New DataGridViewEditingControlShowingEventHandler(AddressOf dataGridView1_EditingControlShowing)
'DataGridView1.DataError += New DataGridViewDataErrorEventHandler(AddressOf dataGridView1_DataError)
End Sub
Private Function CreateComboBoxColumn1() As DataGridViewComboBoxColumn
Dim column As New DataGridViewComboBoxColumn()
If True Then
column.Name = "column2"
column.HeaderText = "Column 2"
column.DropDownWidth = 120
column.Width = 120
column.MaxDropDownItems = 3
column.Items.AddRange(New String() {"First name", "Last name", "E-mail"})
column.FlatStyle = FlatStyle.Flat
End If
Return column
End Function
Private Function CreateComboBoxColumn2() As DataGridViewComboBoxColumn
Dim column As New DataGridViewComboBoxColumn()
If True Then
column.Name = "column3"
column.HeaderText = "Column 3"
column.DropDownWidth = 150
column.Width = 150
column.MaxDropDownItems = 3
column.FlatStyle = FlatStyle.Flat
End If
Return column
End Function
Private Sub PopulatingDGV()
'1.ST COLUMN: some test data to populate dgv
Dim companies As String() = {"Indian Info", "Cybex", "Admin"}
For i As Integer = 0 To companies.Length - 1
dataGridView1.Rows.Add(companies(i))
Next
'2.ND COLUMN: creating a generic list (of your data from the file):
'I will not populate it from the file, only invent some example data:
Dim persons As Person() = New Person() {New Person("Monica", "Trotsky", "monica@test.com"), New Person("Budh", "sagar", "budh@cybex.in")}
list = New List(Of Person)()
For Each p As Person In persons
list.Add(p)
Next
End Sub
Private Sub DataGridView1_EditingControlShowing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing
Try
If DataGridView1.CurrentCell.ColumnIndex = 1 Then
Dim combo As ComboBox = TryCast(e.Control, ComboBox)
If combo IsNot Nothing Then
RemoveHandler combo.SelectedIndexChanged, New EventHandler(AddressOf comboBox_SelectedIndexChanged)
AddHandler combo.SelectedIndexChanged, New EventHandler(AddressOf comboBox_SelectedIndexChanged)
End If
End If
Catch ex As Exception
MessageBox.Show("Error:" & vbLf & vbLf & ex.Message)
End Try
End Sub
Private Sub comboBox_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)
Try
Dim cb As ComboBox = DirectCast(sender, ComboBox)
Dim selection As String = cb.Text
If selection <> [String].Empty Then
For Each dgvColumn As DataGridViewColumn In dataGridView1.Columns
If dgvColumn.Name = "column3" Then
Dim row As Integer = dataGridView1.CurrentCell.RowIndex
Dim cell As DataGridViewComboBoxCell = DirectCast(dataGridView1(2, row), DataGridViewComboBoxCell)
'cell.Items.Clear();
Select Case selection
Case "First name"
If True Then
cell.DataSource = list
cell.DisplayMember = "firstName"
cell.ValueMember = cell.DisplayMember
Exit Select
End If
Case "Last name"
If True Then
cell.DataSource = list
cell.DisplayMember = "lastName"
cell.ValueMember = cell.DisplayMember
Exit Select
End If
Case "E-mail"
If True Then
cell.DataSource = list
cell.DisplayMember = "eMail"
cell.ValueMember = cell.DisplayMember
Exit Select
End If
End Select
End If
Next
End If
Catch ex As Exception
MessageBox.Show("Error:" & vbLf & vbLf & ex.Message)
End Try
End Sub
Friend Class Person
Public Property firstName() As String
Get
Return m_firstName
End Get
Set(ByVal value As String)
m_firstName = Value
End Set
End Property
Private m_firstName As String
Public Property lastName() As String
Get
Return m_lastName
End Get
Set(ByVal value As String)
m_lastName = Value
End Set
End Property
Private m_lastName As String
Public Property eMail() As String
Get
Return m_eMail
End Get
Set(ByVal value As String)
m_eMail = Value
End Set
End Property
Private m_eMail As String
Public Sub New(ByVal _fn As String, ByVal _ln As String, ByVal _em As String)
firstName = _fn
lastName = _ln
eMail = _em
End Sub
End Class
Private Sub DataGridView1_DataError(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewDataErrorEventArgs) Handles DataGridView1.DataError
If e.Exception IsNot Nothing AndAlso e.Context = DataGridViewDataErrorContexts.Commit Then
MessageBox.Show("CustomerID value must be unique.")
End If
End Sub
End Class
精彩评论