הערה
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות להיכנס או לשנות מדריכי כתובות.
הגישה לדף זה מחייבת הרשאה. באפשרותך לנסות לשנות מדריכי כתובות.
Question
Tuesday, March 27, 2012 9:52 PM
I need to force a DataGridView cell to update the underlying DataTable. Here is my situation. I fill a DataTable using my adapters Fill method, then set that DataTable as my DataGridView's datasource. Lets say one of my DataGridView columns is a CheckBox column. If I left-click a checkbox in the first row and then left click a different row in the DataGridView the underlying DataTable_RowChanged event fires, which tells me the first edit I did has gone to the underlying DataTable.
Here is the problem. If I left-click the checkbox in a row and then right-click the column header to display my context menu the DataTable_RowChanged event doesn't fire because the DataGridView row is still in edit mode. I've tried Me.DataGridView.EndEdit(), but that doesn't cause my RowChanged event to fire, why?
I need to ensure my underlying DataTable matches the data in the DataGridView, because I am getting a subset of my original table. See code below.
Private Sub DataGridView1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseDown
' run this block of code if right-clicked
If e.Button = Windows.Forms.MouseButtons.Right Then
' ensure the datagridview data matches the underlying datatable before proceeding
If CType(sender, DataGridView).IsCurrentRowDirty Then Me.DataGridView1.EndEdit()
' get a subset of the original datatable, where CheckBox column is True
Dim dv As DataView = CType(Me.DataGridView1.DataSource, DataTable).AsDataView
dv.RowFilter = "ISNULL(CheckBoxColumn, False) = True"
Dim dt As DataTable = dv.ToTable
Me.DataGridView1.DataSource = dt
' call datagridview column context menu
Me.ShowContextMenu(sender, e, Me.flpPending)
End If
End Sub
Thanks in advance,
Ryan
All replies (5)
Wednesday, March 28, 2012 10:27 PM ✅Answered | 1 vote
Hi Ryan,
Give this code a spin and see if it gives you the behavior you are looking for.
Public Class Form1
Private WithEvents dt As New DataTable
Private WithEvents dgv As New DataGridView
Private WithEvents cm As New ContextMenuStrip
Private WithEvents Item1 As New ToolStripButton With {.Text = "Item1"}
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Size = New Size(400, 300)
With dt
.Columns.Add(New DataColumn("check1", GetType(Boolean)))
.Columns.Add(New DataColumn("check2", GetType(Boolean)))
.Columns.Add(New DataColumn("text1", GetType(String)))
End With
cm.Items.Add(Item1)
dgv.Size = New Size(375, 250)
dgv.DataSource = dt
dgv.EditMode = DataGridViewEditMode.EditOnEnter
dgv.ContextMenuStrip = cm
Me.Controls.Add(dgv)
End Sub
Private Sub cm_Opening(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles cm.Opening
If dgv.CurrentRow.IsNewRow Then Exit Sub
If dgv.CurrentCell.IsInEditMode Then
dgv.EndEdit()
CType(dgv.CurrentRow.DataBoundItem, DataRowView).EndEdit()
End If
End Sub
Private Sub dt_RowChanged(ByVal sender As Object, ByVal e As System.Data.DataRowChangeEventArgs) Handles dt.RowChanged
'write current values to Immediate Window
Debug.WriteLine(String.Format("check1: {0}, check2: {1}, text1: {2}", e.Row(0).ToString, e.Row(1).ToString, e.Row(2).ToString))
End Sub
End Class
Wednesday, March 28, 2012 1:44 PM
Hi Ryan,
How are you?
Would you like to try this workaround?
Private dt As New DataTable
Private Sub TestCheckboxForm_Load2(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
dt.Columns.Add("index")
dt.Columns.Add("yes/No")
dt.Columns(0).DataType = GetType(Integer)
dt.Columns(1).DataType = GetType(Boolean)
dt.Rows.Add(1, True)
dt.Rows.Add(2, True)
dt.Rows.Add(3, True)
'AddHandler dt.RowChanged, AddressOf DataTableRowChanged
Me.DataGridView1.DataSource = dt
End Sub
Private Sub DataGridView1_CurrentCellDirtyStateChanged(sender As Object, e As System.EventArgs) Handles DataGridView1.CurrentCellDirtyStateChanged
If Me.DataGridView1.CurrentCell.ColumnIndex = 1 Then
Me.DataGridView1.EndEdit(DataGridViewDataErrorContexts.Commit)
DataTableRowChanged(dt, New DataRowChangeEventArgs(dt.Rows(Me.DataGridView1.CurrentCell.RowIndex), DataRowAction.Change))
End If
End Sub
When the checkbox value is changed, I manually called the event handler.
Best regards,
Mike Feng
MSDN Community Support | Feedback to us
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Wednesday, March 28, 2012 1:59 PM
Hi Ryan,
When you call the endedit method, the changes are saved into the data table, you can check this will this test code:
Private dt As New DataTable
Private Sub TestCheckboxForm_Load2(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
dt.Columns.Add("index")
dt.Columns.Add("yes/No")
dt.Columns(0).DataType = GetType(Integer)
dt.Columns(1).DataType = GetType(Boolean)
dt.Rows.Add(1, True)
dt.Rows.Add(2, True)
dt.Rows.Add(3, True)
'AddHandler dt.RowChanged, AddressOf DataTableRowChanged
AddHandler dt.ColumnChanged, AddressOf DataTableColChanged
Me.DataGridView1.DataSource = dt
End Sub
Private Sub DataGridView1_CurrentCellDirtyStateChanged(sender As Object, e As System.EventArgs) Handles DataGridView1.CurrentCellDirtyStateChanged
If Me.DataGridView1.CurrentCell.ColumnIndex = 1 Then
Me.DataGridView1.EndEdit()
End If
End Sub
Private Sub DataTableRowChanged(sender As Object, e As DataRowChangeEventArgs)
Console.WriteLine(e.Action)
End Sub
Private Sub DataTableColChanged(sender As Object, e As DataColumnChangeEventArgs)
Console.WriteLine(e.ProposedValue)
End Sub
So would you like to change an event for your goal?
Best regards,
Mike Feng
MSDN Community Support | Feedback to us
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Wednesday, March 28, 2012 5:37 PM
Thanks Mike for the reply. I don't believe the workaround is going to work for me. Although your solution does work for a CheckBox Column, it will not work for a TextBox column in my situation. I update my database whenever a data row is changed in the underlying DataTable_RowChanged event.
I disagree that the EndEdit() method pushes the new DataGridView cell value to the underlying DataTable. If I get a fresh datatable and set it as the DataSource for DataGridView1 then left-click the first row of the DataGridView1 in Column1 (TextBox Column). Type in "test" then right-click the column header. Place this code in the DataGridView1_MouseDown event. The returned DataTable (dt) has no rows in it. This tells me the EndEdit() method is not working as it should or I'm doing something wrong.
Private Sub DataGridView1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseDown
' run this block of code if right-clicked
If e.Button = Windows.Forms.MouseButtons.Right Then
' ensure the datagridview data matches the underlying datatable before proceeding
If CType(sender, DataGridView).IsCurrentRowDirty Then Me.DataGridView1.EndEdit()
' get a subset of the original datatable, where CheckBox column is True
Dim dv As DataView = CType(Me.DataGridView1.DataSource, DataTable).AsDataView
dv.RowFilter = "Column1 = 'test'"
Dim dt As DataTable = dv.ToTable
Me.DataGridView1.DataSource = dt
' call datagridview column context menu
Me.ShowContextMenu(sender, e, Me.flpPending)
End If
End Sub
Ryan
Friday, March 30, 2012 4:08 PM
Thanks TnTinMN!
For some reason adding the line of code below fires the RowChanged event. Seems strange to me you would have to EndEdit() for the DataGridView and the DataBoundItem. I assumed EndEdit() would automatically push the data to the underlying table. I even tried a BindingSource thinking it would push the data for me when dgv.EndEdit() was executed, but nope. I had to EndEdit on the DataBoundItem as well.
CType(dgv.CurrentRow.DataBoundItem, DataRowView).EndEdit()
Ryan