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

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

TL;DR

我用一个 UserForm 有一个动态分配自己的标题和一些控制标题的三个不同的变化。具体到这个UserForm上,有四个 CheckBox 在两个变化中是必需的,而在一个变化中是不可见的。

我的数据验证检查所有的必填字段都有一个输入值(包括四个复选框中的一个被选中),所以当使用不需要勾选复选框的表单时(因为控件不可见),我得到了我的 "Please enter a value into each field." MessageBox.

如何避免这种情况的发生?


我一直在阅读 UserForm1.Show 在过去的几个月里,我和其他许多人一起,帮助我理解了什么是UserForm以及它是如何工作的。

我正试图在我现有的一个项目中实现MVP模式,这个项目或多或少有 只是 已 "完成"。

自然,当我遇到问题或困惑时,我会跳到google,在大多数情况下,要么找到另一篇文章,要么找到一个SO的问题,并有作者比较充分的答案。但是,我找不到一个用于验证一个人的方法。MSForms.Control 可能有,也可能没有--即有时在表格上使用,这取决于表格的变化。

请注意我觉得我设计我的表单的方式可能是错误的(好吧,单一的表单),所以如果是这样的话,一个能确定并涵盖该主题的答案也将是最有帮助的。

所以这是我的基本表单(测试按钮是为了...测试)。snip of design view of userform

当点击这3个按钮中的任何一个(工作表ActiveX命令按钮),它就会被填充到下面的UserForms中(标题与按钮对应)。Worksheet ActiveX Commandbuttons

NEC userform LG userform Other userform

现在,我的数据验证工作正常了。NECLG 形式,但当它到了 其他 形式。这是因为一个 产品类型 CheckBox 是需要的。NECLG 的产品,但不是为了 其他 产品,并且如果没有 产品类型.

在这里,我将包括 CommandButton1_Click (测试按钮)事件和类模块代码。我的数据验证是在UserForm模块中完成的,但我最近在阅读i 把它放在模型中,所以我 认为 我需要把它移到模块中去做所有其他的事情。

用户表格代码模块 - 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

类模块 - TestForm (MCVE)

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. 它是在 IsFormCompleted 功能,因为有23个表单要求这个属性有一个值,但自然不需要表单的 任何产品类型。

我的想法是,简单的解决方法是创建 另一个 分表 其他产品 的版本,它可以有一个独立的数据验证功能,但我想 尝试 保持可维护性,避免这种形式超过1个。

我怎样才能让这种类型的数据验证适应于识别控制的 是否有一个值?

vba userform mvp
1个回答
3
投票

你的模型类被命名为 *Form 我一时糊涂了,我可能把这个名字命名为 "我"。形成 那样 TestView),并用于 TestModel 的模型类 :)

如果viewform的作用是展示数据,那么模型的作用就是,嗯。 的数据。TestProduct 就是这样一个数据。它的有效性是 可观数据. 你可以考虑这样 元数据 肆意妄为,有一些 TestModelValidator 类,实现一些 IModelValidator 界面可能是这样的。

Public Function IsValid() As Boolean
End Function

...但这可能是矫枉过正。如果我们对拥有 模型 负责数据和它的验证,那么模型类可以是这样的。

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

现在 观点 可以操纵模型--而不是这里的情况。

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 事件,然后让模型来驱动UI的状态。

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

希望对你有所帮助!


EditAddendum: 使用模型状态也可以驱动这样的控件是否应该是可见的;你的模型类应该封装尽可能多的逻辑(而不是把它放在表单的代码后面)--这样你就可以很容易地针对你的模型类写测试,验证和记录它的行为,而不需要每次你做一个可能会破坏某些东西的改变时,手动测试实际表单中的每一个边缘情况。 换句话说,如果viewform需要有一个供应商名称的集合来填充组合框或创建尽可能多的复选框控件,那么模型的工作就是封装这些数据。

换句话说,如果你需要一个标志来驱动某个模型逻辑,那么让这个标志成为你模型状态的一部分。

Private Type TState
    '...
    ProductTypes As Collection
End Type

Public Property Get HasProductTypes() As Boolean
    HasProductTypes = this.ProductTypes.Count > 0
End Property

Public Property Get ProductTypes() As Variant
    Dim result(0 To ProductTypes.Count)
    Dim pt As Variant, i As Long
    For Each pt In this.ProductTypes
        result(i) = pt
        i = i + 1
    Next
    ProductTypes = result
End Property

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...

    Dim validProductType As Boolean '<~ model is valid with an empty ProductType if there are no product types
    validProductType = IIf(HasProductTypes, Len(this.ProductType) > 0, True)

    IsValid = validProductName And validProductType
End Property
© www.soinside.com 2019 - 2024. All rights reserved.