筛选条件变更后,如何从DataGridView更新DataTable行数据
解决方案
核心问题原因
你用ItemArray赋值无效的根本原因是:DataRow.ItemArray返回的是当前行数据的副本数组,修改这个副本不会影响原DataRow的实际值,自然也不会同步到DataGridView。
正确的修改方式
直接通过DataRow的列索引或列名赋值,不要使用ItemArray。修改你的ProgressChanged事件代码如下:
Private Sub bgw_PostProcess_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bgw_PostProcess.ProgressChanged Select Case e.ProgressPercentage Case 0 ' 先将UserState转换为DataRowView类型,避免类型隐式转换问题 Dim targetRowView As DataRowView = DirectCast(e.UserState(6), DataRowView) ' 方式1:用列索引直接赋值 targetRowView.Row(1) = e.UserState(5) ' 方式2:用列名赋值(更推荐,避免后续列顺序变化导致错误) ' targetRowView.Row("你的目标列名") = e.UserState(5) ts_Status.Text = "Reading thread (page " & e.UserState(0) & " of " & e.UserState(2) & ")" End Select End Sub
额外优化建议
- 用自定义类替代数组传递参数:
e.UserState数组依赖索引定位参数,极易因索引混乱导致错误,建议创建自定义类封装参数:
Public Class ProcessUpdateArgs Public Property CurrentPage As Integer Public Property TotalPages As Integer Public Property UpdatedValue As Object Public Property TargetRowView As DataRowView ' 可添加其他需要传递的参数 End Class
在DoWork事件中传递该类实例:
bgw_PostProcess.ReportProgress(0, New ProcessUpdateArgs With { .CurrentPage = currentPage, .TotalPages = totalPages, .UpdatedValue = yourCalculatedValue, .TargetRowView = targetRowView })
在ProgressChanged中直接访问属性,代码可读性大幅提升:
Dim updateArgs As ProcessUpdateArgs = DirectCast(e.UserState, ProcessUpdateArgs) updateArgs.TargetRowView.Row(1) = updateArgs.UpdatedValue ts_Status.Text = $"Reading thread (page {updateArgs.CurrentPage} of {updateArgs.TotalPages})"
保障线程安全:
ProgressChanged事件本身运行在UI线程,在此处修改DataRow是安全的,不会触发跨线程异常。避免在DoWork后台线程直接修改绑定数据,统一通过ReportProgress回到UI线程操作,可规避潜在的线程冲突。筛选视图自动同步:只要修改的是
DataRowView.Row(即底层DataTable的行数据),无论DataGridView是否处于筛选状态,UI都会自动同步更新——因为DataGridView绑定的是DataTable的视图,底层数据变更会自动映射到界面。
内容的提问来源于stack exchange,提问作者Gary L Smith
相关产品推荐
相关产品推荐

