Conditional Read-Only Columns in DataGridView
C# version here.
A couple of people have asked a similar questions recently so I thought I'd post the advice I provided here as it may help others too. The first person asked how to retrieve data from a database and display it in a DataGridView without the user being able to edit the data in certain columns, while still allowing the user to enter data into that column for new records and also edit that column for records that have been previously added in the current session. Here's the code I provided:
vb.net Code:
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles MyBase.Load
Dim table As New DataTable
With table.Columns
.Add("ID", GetType(Integer)).AutoIncrement = True
.Add("Name", GetType(String))
End With
With table.Rows
.Add(Nothing, "Peter")
.Add(Nothing, "Paul")
.Add(Nothing, "Mary")
End With
'Set all RowStates to Unchanged, as they would be
'if the data had been retrieved from a database.
table.AcceptChanges()
'Bind the data to the grid through the BindingSource.
Me.BindingSource1.DataSource = table
Me.DataGridView1.DataSource = Me.BindingSource1
'Make the Name column read-only by default.
Me.DataGridView1.Columns(1).ReadOnly = True
End Sub
Private Sub BindingSource1_CurrentChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles BindingSource1.CurrentChanged
'Make sure the grid has columns, which it won't when the BindingSource is first bound.
If Me.DataGridView1.ColumnCount > 0 Then
'Get the underlying DataRow that corresponds to the selected row in the grid.
Dim row As DataRow = DirectCast(Me.BindingSource1.Current, DataRowView).Row
'Only allow editing if the row is detached (created but not yet added to the table)
'or added (added to the table since the last AcceptChanges call).
Me.DataGridView1.Columns(1).ReadOnly = Not (row.RowState = DataRowState.Detached OrElse _
row.RowState = DataRowState.Added)
End If
End Sub
That code assumes that you've added a DataGridView and a BindingSource to your form.
Note that, when the user selects a row in the grid, the CurrentChanged event of the BindingSource is raised. The code gets the underlying DataRow and only allows the second column to be edited if that row has a RowState of Detached or Added. Detached corresponds to the last row in the grid. When the user starts adding data there it creates a new DataRow but it doesn't get added to the DataTable until you navigate away from that row. As soon as you navigate away from that row the DataRow gets added to the DataTable and its RowState becomes Added.
Someone else asked how to disable editing in all but the last row. The answer was to remove the test for a RowState of Added and just test for Detached. It's worth noting, though, that, if you do that, the user won't be able to change the data in new rows once they've added them if they realise they've entered the wrong value.
1 Attachment(s)
Re: Conditional Read-Only Columns in DataGridView
Quote:
Originally Posted by
jmcilhinney
C# version
here.
A couple of people have asked a similar questions recently so I thought I'd post the advice I provided here as it may help others too. The first person asked how to retrieve data from a database and display it in a DataGridView without the user being able to edit the data in certain columns, while still allowing the user to enter data into that column for new records and also edit that column for records that have been previously added in the current session. Here's the code I provided:
vb.net Code:
Private Sub Form1_Load(ByVal sender As Object, _
ByVal e As EventArgs) Handles MyBase.Load
Dim table As New DataTable
With table.Columns
.Add("ID", GetType(Integer)).AutoIncrement = True
.Add("Name", GetType(String))
End With
With table.Rows
.Add(Nothing, "Peter")
.Add(Nothing, "Paul")
.Add(Nothing, "Mary")
End With
'Set all RowStates to Unchanged, as they would be
'if the data had been retrieved from a database.
table.AcceptChanges()
'Bind the data to the grid through the BindingSource.
Me.BindingSource1.DataSource = table
Me.DataGridView1.DataSource = Me.BindingSource1
'Make the Name column read-only by default.
Me.DataGridView1.Columns(1).ReadOnly = True
End Sub
Private Sub BindingSource1_CurrentChanged(ByVal sender As Object, _
ByVal e As EventArgs) Handles BindingSource1.CurrentChanged
'Make sure the grid has columns, which it won't when the BindingSource is first bound.
If Me.DataGridView1.ColumnCount > 0 Then
'Get the underlying DataRow that corresponds to the selected row in the grid.
Dim row As DataRow = DirectCast(Me.BindingSource1.Current, DataRowView).Row
'Only allow editing if the row is detached (created but not yet added to the table)
'or added (added to the table since the last AcceptChanges call).
Me.DataGridView1.Columns(1).ReadOnly = Not (row.RowState = DataRowState.Detached OrElse _
row.RowState = DataRowState.Added)
End If
End Sub
That code assumes that you've added a DataGridView and a BindingSource to your form.
Note that, when the user selects a row in the grid, the CurrentChanged event of the BindingSource is raised. The code gets the underlying DataRow and only allows the second column to be edited if that row has a RowState of Detached or Added. Detached corresponds to the last row in the grid. When the user starts adding data there it creates a new DataRow but it doesn't get added to the DataTable until you navigate away from that row. As soon as you navigate away from that row the DataRow gets added to the DataTable and its RowState becomes Added.
Someone else asked how to disable editing in all but the last row. The answer was to remove the test for a RowState of Added and just test for Detached. It's worth noting, though, that, if you do that, the user won't be able to change the data in new rows once they've added them if they realise they've entered the wrong value.
I get this error when trying to use your code..Attachment 93701
pic attached..
Re: Conditional Read-Only Columns in DataGridView
I figured it out....should use binding not grid..thanks! great post!