我使用一个UserForm
,它具有自己的字幕的动态分配和带有三种不同变体的某些控制字幕。特别是在此用户窗体上,两个变体需要四个CheckBox
,并且在一个变体中不可见。
我的数据验证检查所有必填字段都输入了一个值(包括四个复选框中的一个已选中),因此,当使用不需要勾选复选框的表单时(因为控件不可见),我得到了[ C0]
如何避免这种情况?
过去几个月我一直在阅读"Please enter a value into each field." MessageBox.
,对我自己和其他许多人来说,这帮助我了解了UserForm是什么以及它如何工作。
[我正在尝试将MVP模式实施到我已经或多或少地[[just已“完成”的现有项目中。
[自然,当我遇到问题或困惑时,我会跳到google,在大多数情况下,或者找到另一篇文章或一个SO问题,而作者的答案也足够多。但。我找不到用于验证可能存在或可能不存在的UserForm1.Show的方法-即有时在表单上使用,具体取决于表单的变化形式。[请注意
,我觉得我设计表单的方式可能不对(嗯,单数形式),因此,在这种情况下,可以识别并确定答案的答案涵盖该主题也将最有帮助!所以这是我的基本表单(测试按钮用于...测试):MSForms.Control
并且当单击这三个按钮中的任何一个时(工作表ActiveX命令按钮),它会填充以下用户窗体之一(标题与按钮相对应):
现在,我的数据验证在
NEC和LG表单上工作正常,但是在进入Other表单时失败。这是因为NEC和LG产品需要一个产品类型 ,而对于Other产品则不需要,并且如果没有< [产品类型。
在这里,我将包含CheckBox
(测试按钮)事件和类模块代码。我的数据验证是在UserForm模块中完成的,但是最近我正在阅读[将其放在模型中,所以我认为我需要将其移至执行其他所有操作的模块中。 UserForm代码模块-MCVECommandButton1_Click
类模块-TestForm(MCVE)Option Explicit
Public DataEntryForm As New TestForm
Private Sub CommandButton1_Click()
With Me
If .CheckBox1.Value = True Then
DataEntryForm.TestProduct = .CheckBox1.Caption
ElseIf .CheckBox2.Value = True Then
DataEntryForm.TestProduct = .CheckBox2.Caption
ElseIf .CheckBox3.Value = True Then
DataEntryForm.TestProduct = .CheckBox3.Caption
ElseIf .CheckBox4.Value = True Then
DataEntryForm.TestProduct = .CheckBox4.Caption
End If
End With
If Not FormIsComplete Then
MsgBox "Please enter a value into each field.", vbCritical, "Missing Values"
Exit Sub
End If
End Sub
Private Function FormIsComplete() As Boolean
FormIsComplete = False
If DataEntryForm.TestProduct = "" Then Exit Function
FormIsComplete = True
End Function
所以,更具体地说;
问题出在
Private pTestProduct As String
Public Property Get TestProduct() As String
TestProduct = pTestProduct
End Property
Public Property Let TestProduct(NewValue As String)
pTestProduct = NewValue
End Property
。它在DataEntryForm.TestProduct
函数中,因为2/3表格要求此属性具有值,但是对于<< without >>任何产品类型的表格,自然是不需要的。 我的想法是简单的解决方法是为
Other Products
another单独的表单,该表单可以具有单独的数据验证功能,但是我想try保持可维护性并避免具有超过此表单的1个。
我如何使这种类型的数据验证适应识别控件应该
是否具有值? TL; DR我使用了一个UserForm,它动态分配了自己的标题和带有三个不同变体的某些控件标题。特别是在此用户窗体上,在两个...上需要四个CheckBox ...也可呈现数据。您可以考虑使用metadata并疯狂使用一些TestProduct
类,该类实现一些可能看起来像这样的TestModelValidator
接口:
IModelValidator
Public Function IsValid() As Boolean
End Function
现在view可以操纵模型-此处不发生什么:
Option Explicit
Private Type TState
ValidationErrors As Collection
ProductName As String
'...other state members
End Type
Private this As TState
Private Sub Class_Initialize()
Set this.ValidationErrors = New Collection
End Sub
Public Property Get ProductName() As String
ProductName = this.ProductName
End Property
Public Property Let ProductName(ByVal value As String)
this.ProductName = value
End Property
'...other model properties...
Public Property Get IsValid() As Boolean
Dim validProductName As Boolean
validProductName = Len(this.ProductName) <> 0
this.ValidationErrors.Remove "ProductName" '<~ NOTE air code, verify this works
If Not validProductName Then this.ValidationErrors("ProductName") = "Product name cannot be empty"
'...validation logic for other properties...
IsValid = validProductName
End Property
Public Property Get ValidationErrors() As String
ReDim result(0 To this.ValidationErrors.Count)
Dim e As Variant, i As Long
For Each e In this.ValidationErrors
result(i) = e
i = i + 1
Next
ValidationErrors = Join(vbNewLine, result)
End Property
代替查询UI,监听当UI告诉您正在发生什么时-处理每个控件的
Private Sub CommandButton1_Click() With Me If .CheckBox1.Value = True Then DataEntryForm.TestProduct = .CheckBox1.Caption ElseIf .CheckBox2.Value = True Then DataEntryForm.TestProduct = .CheckBox2.Caption
事件,然后让模型驱动UI状态:
Change
希望有帮助!编辑/附录:使用模型状态还可以驱动该控件或控件是否可见;您的模型类应该封装尽可能多的逻辑(与在表单的代码中隐藏代码相比)-这样,您可以轻松地针对模型类编写测试以验证并记录其行为,而无需手动测试每个极端情况每次进行实际更改时都可能会破坏某些东西!换句话说,如果视图/表单需要具有供应商名称的集合以填充组合框或创建尽可能多的复选框控件,则封装此数据是模型的工作。
换句话说,如果您需要一个标志来驱动某些模型逻辑,请将该标志作为模型状态的一部分:Private Sub CheckBox1_Change() If Me.CheckBox1.Value Then Model.ProductName = Me.CheckBox1.Caption Validate End If End Sub Private Sub CheckBox2_Change() If Me.CheckBox2.Value Then Model.ProductName = Me.CheckBox2.Caption Validate End If End Sub Private Sub CodeBox_Change() Model.Code = CodeBox.Text Validate End Sub Private Sub DescriptionBox_Change() Model.Description = DescriptionBox.Text Validate End Sub Private Sub Validate() Dim valid As Boolean valid = Model.IsValid Me.OkButton.Enabled = valid Me.ValidationErrorsLabel.Caption = Model.ValidationErrors Me.ValidationErrorsLabel.Visible = Not valid End Sub