VBA中ModelClass的Property Let内处理数据输入错误并通知ViewClass的最佳方法
嘿,针对你在VBA的ModelClass里想在Property Let中通知ViewClass数据输入错误的需求,我整理了几个在VBA环境下非常实用的最佳方案,一起来看看:
方案1:自定义事件(推荐,解耦首选)
这是MVVM模式下最常用的解耦方式,Model只负责触发事件,View负责订阅并处理事件,两者之间不需要直接依赖具体实现。
步骤1:在ModelClass中定义事件
在ModelClass的声明部分添加自定义事件,用来传递错误信息和对应的属性名:
Option Compare Database Option Explicit Private m_idCompra As String ' 定义验证错误事件,传递错误信息和属性名称 Public Event ValidationError(message As String, propertyName As String) ' 定义属性更新成功事件(可选,通知View数据已更新) Public Event PropertyUpdated(propertyName As String, newValue As Variant) Public Property Get codCompra() As String codCompra = m_idCompra End Property Public Property Let codCompra(ByVal codigoCompra As String) If Len(codigoCompra) = 0 Then ' 触发错误事件,传递错误信息和属性名 RaiseEvent ValidationError("采购编码不能为空!", "codCompra") ElseIf Not IsNumeric(codigoCompra) Then RaiseEvent ValidationError("采购编码必须为数字格式!", "codCompra") Else m_idCompra = codigoCompra ' 可选:触发属性更新成功事件 RaiseEvent PropertyUpdated("codCompra", codigoCompra) End If End Property
步骤2:在ViewClass中订阅事件
在ViewClass里用WithEvents声明Model实例,然后编写事件处理过程:
Option Compare Database Option Explicit ' 用WithEvents声明,才能订阅Model的事件 Private WithEvents m_model As ModelClass Public Sub Initialize(model As ModelClass) Set m_model = model End Sub ' 处理Model的验证错误事件 Private Sub m_model_ValidationError(message As String, propertyName As String) ' 这里写View的处理逻辑,比如弹出提示、高亮输入框等 MsgBox "输入错误:" & message, vbExclamation, "验证失败" ' 示例:如果View有对应控件,可以定位到错误控件 ' Me.txtCodCompra.SetFocus End Sub ' 处理属性更新成功事件(可选) Private Sub m_model_PropertyUpdated(propertyName As String, newValue As Variant) ' 比如更新View上的显示 ' Me.txtCodCompra.Value = newValue End Sub
这种方式的好处是Model和View完全解耦,Model不需要知道View的具体类型,只要触发事件就行,扩展性很强。
方案2:回调函数(适合简单一对一场景)
如果你的场景比较简单,Model和View是一对一绑定的,可以让View把一个回调方法传递给Model,Model在出错时直接调用这个方法。
步骤1:在ModelClass中添加回调引用
Option Compare Database Option Explicit Private m_idCompra As String ' 保存View的回调对象 Private m_validationCallback As Object ' 让View设置回调对象 Public Property Set ValidationCallback(obj As Object) Set m_validationCallback = obj End Property Public Property Get codCompra() As String codCompra = m_idCompra End Property Public Property Let codCompra(ByVal codigoCompra As String) If Len(codigoCompra) = 0 Then ' 调用View的回调方法 If Not m_validationCallback Is Nothing Then m_validationCallback.OnValidationError "采购编码不能为空!", "codCompra" End If ElseIf Not IsNumeric(codigoCompra) Then If Not m_validationCallback Is Nothing Then m_validationCallback.OnValidationError "采购编码必须为数字格式!", "codCompra" End If Else m_idCompra = codigoCompra ' 可选:调用更新成功的回调 If Not m_validationCallback Is Nothing Then m_validationCallback.OnPropertyUpdated "codCompra", codigoCompra End If End If End Property
步骤2:在ViewClass中实现回调方法
Option Compare Database Option Explicit Private m_model As ModelClass Public Sub Initialize(model As ModelClass) Set m_model = model ' 把自己设置为Model的回调对象 Set m_model.ValidationCallback = Me End Sub ' 实现Model需要的回调方法 Public Sub OnValidationError(message As String, propertyName As String) MsgBox "输入错误:" & message, vbExclamation, "验证失败" ' 其他View处理逻辑 End Sub Public Sub OnPropertyUpdated(propertyName As String, newValue As Variant) ' 更新View显示 End Sub
这个方案实现起来更简单,但耦合度比事件高一点,适合小型项目或者简单的界面场景。
方案3:抛出自定义错误(适合需要中断流程的场景)
如果希望在输入错误时直接中断赋值流程,并且让View处理错误,可以抛出自定义错误,然后View在赋值时捕获错误。
步骤1:在ModelClass中抛出错误
Option Compare Database Option Explicit Private m_idCompra As String Public Property Get codCompra() As String codCompra = m_idCompra End Property Public Property Let codCompra(ByVal codigoCompra As String) If Len(codigoCompra) = 0 Then ' 抛出自定义错误,错误码用vbObjectError + 自定义编号(避免和系统错误冲突) Err.Raise vbObjectError + 1001, "ModelClass.codCompra", "采购编码不能为空!" ElseIf Not IsNumeric(codigoCompra) Then Err.Raise vbObjectError + 1002, "ModelClass.codCompra", "采购编码必须为数字格式!" Else m_idCompra = codigoCompra End If End Property
步骤2:在ViewClass中捕获错误
Option Compare Database Option Explicit Private m_model As ModelClass Public Sub AssignCodCompra(value As String) On Error GoTo ErrorHandler m_model.codCompra = value ' 如果没有错误,执行成功逻辑 MsgBox "编码设置成功!", vbInformation Exit Sub ErrorHandler: ' 处理错误信息 MsgBox "输入错误:" & Err.Description, vbExclamation, "验证失败" ' 可以根据错误码做不同处理 Select Case Err.Number Case vbObjectError + 1001 Me.txtCodCompra.SetFocus Case vbObjectError + 1002 Me.txtCodCompra.SelStart = 0 Me.txtCodCompra.SelLength = Len(Me.txtCodCompra.Text) End Select End Sub
这种方式适合需要严格中断流程的场景,但Model和View的耦合度也比较高,因为View需要知道Model的错误码或者错误信息格式。
最后总结一下:
- 如果追求解耦和扩展性,优先选自定义事件方案;
- 如果是简单场景,选回调函数更快捷;
- 如果需要中断流程并强制处理错误,选抛出自定义错误。
内容的提问来源于stack exchange,提问作者Alex Boorjs
相关产品推荐
相关产品推荐

