在VB.Net的ObjectListView中实现行内列值联动计算
解决ObjectListView行内值变更后自动计算同行列的问题
核心问题分析
你当前代码的主要问题是没有获取到当前编辑行的实际ClientTask对象,反而新建了空对象,导致计算逻辑基于空值执行,同时没有将计算结果更新回原数据模型。另外BuildList()会刷新整个列表,效率低下,应该只刷新当前行。
正确实现步骤
- 通过
CellEditFinished事件(比CellEditFinishing更适合,确保编辑值已提交到模型)获取当前行的ClientTask实例 - 根据修改的列类型,重新计算
Qty和Amount - 通知
ObjectListView刷新当前行,而非全量刷新
修正后的代码
Private Sub dlvEstimateTemplate_CellEditFinished(sender As Object, e As CellEditEventArgs) Handles dlvEstimateTemplate.CellEditFinished ' 获取当前编辑行的ClientTask对象,用TryCast避免类型转换异常 Dim currentTask As Entities.ClientTask = TryCast(e.RowObject, Entities.ClientTask) If currentTask Is Nothing Then Return ' 转换失败直接退出 ' 确保数值类型转换安全,避免输入非数字导致异常 Dim inputVal As Single = 0 If Not Single.TryParse(e.NewValue.ToString(), inputVal) Then Return Select Case e.Column.AspectName Case "Length" currentTask.Length = inputVal ' 重新计算Qty和Amount currentTask.Qty = currentTask.Length * currentTask.Height currentTask.Amt = currentTask.Qty * currentTask.Rate Case "Height" currentTask.Height = inputVal currentTask.Qty = currentTask.Length * currentTask.Height currentTask.Amt = currentTask.Qty * currentTask.Rate Case "Rate" currentTask.Rate = inputVal currentTask.Amt = currentTask.Qty * currentTask.Rate End Select ' 只刷新当前行,比BuildList()效率更高 DirectCast(sender, BrightIdeasSoftware.ObjectListView).RefreshObject(currentTask) End Sub
关键说明
- 获取行对象:
TryCast(e.RowObject, Entities.ClientTask)是安全获取当前行数据模型的方式,避免强制转换的异常 - 数值安全转换:用
Single.TryParse处理用户输入,防止非数字内容导致程序崩溃 - 局部刷新:
RefreshObject(currentTask)只会更新当前行的显示,远优于全量刷新的BuildList() - 覆盖所有触发列:处理
Length、Height和Rate列的变更,完整覆盖Qty和Amount的计算逻辑
额外优化建议
如果希望计算逻辑更内聚,可以把Qty和Amount的计算逻辑封装到ClientTask类的属性中,这样属性变更时自动触发计算:
Public Class ClientTask Private _length As Single Private _height As Single Private _rate As Single Public Property Length As Single Get Return _length End Get Set(value As Single) _length = value RecalculateValues() End Set End Property Public Property Height As Single Get Return _height End Get Set(value As Single) _height = value RecalculateValues() End Set End Property Public Property Rate As Single Get Return _rate End Get Set(value As Single) _rate = value RecalculateValues() End Set End Property Public Property Qty As Single Public Property Amt As Single Private Sub RecalculateValues() Qty = Length * Height Amt = Qty * Rate End Sub End Class
此时事件代码可简化为:
Private Sub dlvEstimateTemplate_CellEditFinished(sender As Object, e As CellEditEventArgs) Handles dlvEstimateTemplate.CellEditFinished Dim currentTask As Entities.ClientTask = TryCast(e.RowObject, Entities.ClientTask) If currentTask Is Nothing Then Return Dim inputVal As Single = 0 If Single.TryParse(e.NewValue.ToString(), inputVal) Then Select Case e.Column.AspectName Case "Length" : currentTask.Length = inputVal Case "Height" : currentTask.Height = inputVal Case "Rate" : currentTask.Rate = inputVal End Select DirectCast(sender, BrightIdeasSoftware.ObjectListView).RefreshObject(currentTask) End If End Sub
内容的提问来源于stack exchange,提问作者Pankaj
相关产品推荐
相关产品推荐

