使用MVP方法验证控件是动态的用户表单输入

问题描述 投票:2回答:1

TL; DR

我使用一个UserForm,它具有自己的字幕的动态分配和带有三种不同变体的某些控制字幕。特别是在此用户窗体上,两个变体需要四个CheckBox,并且在一个变体中不可见。

我的数据验证检查所有必填字段都输入了一个值(包括四个复选框中的一个已选中),因此,当使用不需要勾选复选框的表单时(因为控件不可见),我得到了[ C0]

如何避免这种情况?


过去几个月我一直在阅读"Please enter a value into each field." MessageBox.,对我自己和其他许多人来说,这帮助我了解了UserForm是什么以及它如何工作。

[我正在尝试将MVP模式实施到我已经或多或少地[[just已“完成”的现有项目中。

[自然,当我遇到问题或困惑时,我会跳到google,在大多数情况下,或者找到另一篇文章或一个SO问题,而作者的答案也足够多。但。我找不到用于验证可能存在或可能不存在的UserForm1.Show的方法-即有时在表单上使用,具体取决于表单的变化形式。

[请注意

,我觉得我设计表单的方式可能不对(嗯,单数形式),因此,在这种情况下,可以识别并确定答案的答案涵盖该主题也将最有帮助!所以这是我的基本表单(测试按钮用于...测试):MSForms.Control

并且当单击这三个按钮中的任何一个时(工作表ActiveX命令按钮),它会填充以下用户窗体之一(标题与按钮相对应):snip of design view of userform

[Worksheet ActiveX CommandbuttonsNEC userformLG userform

现在,我的数据验证在

NEC和LG表单上工作正常,但是在进入Other表单时失败。这是因为NECLG产品需要一个产品类型 Other userform,而对于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 ...
vba userform mvp
1个回答
3
投票
其有效性是

也可呈现数据。您可以考虑使用metadata并疯狂使用一些TestProduct类,该类实现一些可能看起来像这样的TestModelValidator接口:

IModelValidator

...但是那可能太过分了。如果我们愿意让model负责数据及其验证,那么模型类可能看起来像这样: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
    
© www.soinside.com 2019 - 2024. All rights reserved.