vb.net 检测 DataGridView 中单元格值已被用户更改的行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27067939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 18:30:42  来源:igfitidea点击:

Detect rows in DataGridView whose cell values have been changed by user

vb.netwinformsdatagridview

提问by marky

I have a VB.NET WinForms project that I'm building in VS2013. In a DataGridView bound to a DataSet I want to highlight each row that the user has changed - and if the user changes a row's contents back to its original values (as compared to the database values) I want to remove the highlighting.

我有一个在 VS2013 中构建的 VB.NET WinForms 项目。在绑定到 DataSet 的 DataGridView 中,我想突出显示用户更改的每一行 - 如果用户将行的内容更改回其原始值(与数据库值相比),我想删除突出显示。

I have been Googling for a while now and really haven't gotten anywhere.

我已经在谷歌上搜索了一段时间,但真的一无所获。

All I know at this point is that EmployeesDataSet.HasChanges(DataRowState.Modified)returns False in the CellValueChanged event after having changed text in a cell and clicked out of the row.

在这一点上我所知道的是,EmployeesDataSet.HasChanges(DataRowState.Modified)在更改单元格中的文本并单击该行后,在 CellValueChanged 事件中返回 False。

My assumption is that the overall method would be something like on KeyUp event compare the current row's cell values to the DataSet (or BindingSource or TableAdapter?) and if anything is different, highlight the row, otherwise set the row to the default backcolor.

我的假设是整体方法类似于 KeyUp 事件,将当前行的单元格值与 DataSet(或 BindingSource 或 TableAdapter?)进行比较,如果有任何不同,则突出显示该行,否则将该行设置为默认背景色。

But if that's the right approach I don't understand what I would compare the row's contents to. Would it be the DataSet? The TableAdapter? The BindingSource? If it's one of those, how to I compare the correct row?

但如果这是正确的方法,我不明白我会将行的内容与什么进行比较。会是数据集吗?表适配器?绑定源?如果是其中之一,我该如何比较正确的行?

UPDATE

更新

Some more research has made some progress:

更多的研究取得了一些进展:

I found this iteration code:

我找到了这个迭代代码:

Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()

For Each dt As DataTable In dsChanged.Tables
    For Each row As DataRow In dt.Rows
        For i As Integer = 0 To dt.Columns.Count - 1
            Dim currentBackColor As System.Drawing.Color = dgvEmployees.AlternatingRowsDefaultCellStyle.BackColor
            If Not row(i, DataRowVersion.Current).Equals(row(i, DataRowVersion.Original)) Then
                dgvEmployees.Rows(dt.Rows.IndexOf(row)).DefaultCellStyle.BackColor = Color.LightPink
            Else
                ' No changes so set it to its original color
                dgvEmployees.Rows(dt.Rows.IndexOf(row)).DefaultCellStyle.BackColor = currentBackColor
            End If
        Next
    Next
Next

I put this in a separate Sub, which is being called in the DataGridView.CellValueChanged event.

我把它放在一个单独的 Sub 中,它在 DataGridView.CellValueChanged 事件中被调用。

That correctly detects the rows that have changed cell values, but my code to color the background isn't quite right. As is, it is coloring each successive row from top to bottom as I make changes - regardless of what row in the DGV I edit.

这正确地检测到已更改单元格值的行,但我为背景着色的代码不太正确。照原样,当我进行更改时,它会从上到下为每个连续的行着色 - 无论我编辑 DGV 中的哪一行。

I assumed that dt.Rows.IndexOf(row) would correctly get the correct index of the DGV, since I'm iterating through the DGV's DataTable.

我认为 dt.Rows.IndexOf(row) 会正确获得 DGV 的正确索引,因为我正在遍历 DGV 的 DataTable。

采纳答案by marky

Well, if you go hunting long enough and spend enough time trying different things, you'll eventually find an answer...

好吧,如果你去打猎足够长的时间并花足够的时间尝试不同的事情,你最终会找到答案......

Here's the working code I ended up with:

这是我最终得到的工作代码:

Private Sub dgvEmployees_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvEmployees.CellValueChanged
    ' Pass the row and cell indexes to the method so we can change the color of the correct row
    CompareDgvToDataSource(e.RowIndex, e.ColumnIndex)
End Sub

Private Sub CompareDgvToDataSource(ByVal rowIndex As Integer, ByVal columnIndex As Integer)

    If Not dgvEmployees Is Nothing And dgvEmployees.Rows.Count > 0 Then
        ' Condition required because this Method is also called when the DGV is being built and populated
        Console.WriteLine("rowIndex: " & rowIndex.ToString() & ", columnIndex: " & columnIndex.ToString() & ", cell value: " & dgvEmployees.Rows(rowIndex).Cells(columnIndex).Value.ToString())
    End If

    ' Force ending Edit mode so the last edited value is committed
    EmployeesBindingSource.EndEdit()

    Dim dsChanged As DataSet = EmployeesDataSet.GetChanges()

    If Not dsChanged Is Nothing Then

        For Each dt As DataTable In dsChanged.Tables
            For Each row As DataRow In dt.Rows
                For i As Integer = 0 To dt.Columns.Count - 1
                    If Not row(i, DataRowVersion.Current).Equals(row(i, DataRowVersion.Original)) Then
                        Console.WriteLine("Row index: " & dt.Rows.IndexOf(row))
                        dgvEmployees.Rows(rowIndex).DefaultCellStyle.BackColor = Color.LightPink
                    End If
                Next
            Next
        Next
    End If
End Sub

A couple of notes:

一些注意事项:

Without calling EndEdit() on the BindingSource the changes won't be detected since this is being called by the CellValueChanged, which happens beforethe BindingSource is changed.

如果不对 BindingSource 调用 EndEdit(),则不会检测到更改,因为这是由 CellValueChanged 调用的,这发生BindingSource 更改之前

I tried adding an Else clause to set the BackColor to the original color (for when the DGV row is detected to be the same as the DataSet's row or when validation fails), but I can't figure out how to account for the DGV.AlternatingRowsDefaultCellStyle.BackColor property being set. Ideas???

我尝试添加一个 Else 子句将 BackColor 设置为原始颜色(当检测到 DGV 行与 DataSet 的行相同或验证失败时),但我不知道如何考虑 DGV。正在设置 AlternatingRowsDefaultCellStyle.BackColor 属性。想法???

I think this could be improved by, since I have the row and column indexes in the Method, just going directly to the DataSet's/DataTable's corresponding row and comparing just that, instead of iterating through the entire DataSet. Ideas on that one would be appreciated, but I'll do some more testing to see if I can get it (I figured it out myself this far...)

我认为这可以改进,因为我在方法中有行和列索引,只需直接转到数据集/数据表的相应行并进行比较,而不是遍历整个数据集。对此的想法将不胜感激,但我会做更多的测试,看看我是否能得到它(到目前为止我自己已经弄清楚了......)