VB.NET监听多层嵌套对象mass属性变更并触发总质量重算的实现方案
需求说明
现有简化代码结构如下:
Public Class Main Public world As World Public totalWorldMass As Double '任意world内对象的mass变更时,需调用该方法 Sub RecalculateTotalMass() totalWorldMass = world.object1.mass + world.object2.mass + world.object3.mass End Sub End Class Public Class World Public Property object1 As objectWithMass Public Property object2 As objectWithMass Public Property object3 As objectWithMass '其他属性和方法 End Class Public Class ObjectWithMass Public Property name As String Public Property mass As Double '其他属性和方法 End Class
核心要求:Main类监听world实例,只要World中任意ObjectWithMass类型对象的mass属性发生变更,就执行RecalculateTotalMass方法,无需逐个指定监听对象,不借助反射实现。
实现方案
步骤1:给ObjectWithMass实现INotifyPropertyChanged接口
将事件触发逻辑封装在mass属性的setter中,只有mass变更时才触发事件,减少不必要的计算:
Imports System.ComponentModel Public Class ObjectWithMass Implements INotifyPropertyChanged Private _name As String Private _mass As Double Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged Public Property name As String Get Return _name End Get Set(value As String) _name = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(name))) End Set End Property Public Property mass As Double Get Return _mass End Get Set(value As Double) _mass = value RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(NameOf(mass))) End Set End Property '其他属性和方法 End Class
步骤2:在World类中封装统一的MassChanged事件
将子对象的监听逻辑封装在World内部,对外只暴露统一的质量变更事件,自动处理子对象引用更换的场景:
Imports System.ComponentModel Public Class World Private _object1 As ObjectWithMass Private _object2 As ObjectWithMass Private _object3 As ObjectWithMass '对外暴露的统一事件,所有子对象mass变更都会触发该事件 Public Event MassChanged As EventHandler Public Property object1 As ObjectWithMass Get Return _object1 End Get Set(value As ObjectWithMass) '移除旧对象的监听 If _object1 IsNot Nothing Then RemoveHandler _object1.PropertyChanged, AddressOf HandleChildMassChanged End If _object1 = value '给新对象添加监听 If _object1 IsNot Nothing Then AddHandler _object1.PropertyChanged, AddressOf HandleChildMassChanged End If End Set End Property 'object2、object3写法和object1完全一致 Public Property object2 As ObjectWithMass Get Return _object2 End Get Set(value As ObjectWithMass) If _object2 IsNot Nothing Then RemoveHandler _object2.PropertyChanged, AddressOf HandleChildMassChanged End If _object2 = value If _object2 IsNot Nothing Then AddHandler _object2.PropertyChanged, AddressOf HandleChildMassChanged End If End Set End Property Public Property object3 As ObjectWithMass Get Return _object3 End Get Set(value As ObjectWithMass) If _object3 IsNot Nothing Then RemoveHandler _object3.PropertyChanged, AddressOf HandleChildMassChanged End If _object3 = value If _object3 IsNot Nothing Then AddHandler _object3.PropertyChanged, AddressOf HandleChildMassChanged End If End Set End Property '内部处理子对象的属性变更事件 Private Sub HandleChildMassChanged(sender As Object, e As PropertyChangedEventArgs) If e.PropertyName = NameOf(ObjectWithMass.mass) Then RaiseEvent MassChanged(Me, EventArgs.Empty) End If End Sub '其他属性和方法 End Class
步骤3:在Main类中绑定World的统一事件
Public Class Main '给world添加WithEvents关键字 Public WithEvents world As World Public totalWorldMass As Double Sub RecalculateTotalMass() totalWorldMass = world.object1.mass + world.object2.mass + world.object3.mass End Sub '直接绑定world的MassChanged事件即可 Private Sub HandleWorldMassChanged() Handles world.MassChanged RecalculateTotalMass() End Sub End Class
方案特点
- 无反射依赖,性能表现更好
- 无需在
Main类中逐个绑定子对象事件,后续World新增带mass的属性时,Main代码无需改动 - 自动适配子对象引用更换的场景,不会出现事件漏触发问题
内容的提问来源于stack exchange,提问作者Justin8051
相关产品推荐
相关产品推荐

