MVPアプローチを使用して、コントロールが動的であるユーザーフォーム入力を検証します

サミュエルエバーソン

TL; DR

UserFormは、独自のキャプションと3つの異なるバリエーションを持ついくつかのコントロールキャプションが動的に割り当てられているものを使用します特にこのユーザーフォームでCheckBoxは、2つのバリエーションで4つが必要であり、1つでは表示されません。

私のデータ検証では、すべての必須フィールドに値が入力されていることを確認します(4つのチェックボックスの1つがチェックされていることを含む)ので、チェックボックスをオンにする必要のないフォームを使用すると(コントロールが表示されないため)、 "Please enter a value into each field." MessageBox.

どうすればこれを回避できますか?


私は過去数か月にわたってUserForm1.Show読んでいますが、これは私自身と他の多くの人にとって、UserFormとは何かとその仕組みを理解するのに役立ちました。

多かれ少なかれ「完了」したばかりの既存のプロジェクトにMVPパターンを実装しようとしています

当然、問題や混乱に遭遇すると、グーグルにジャンプし、ほとんどの場合、著者からの十分な回答を含む別の記事またはSOの質問を見つけます。だが。MSForms.Controlそこにあるかもしれないし、ないかもしれないを検証するためのものを見つけることができません-つまり、フォームのバリエーションによっては、フォームで使用されることがあります。

注意してください、私はおそらく自分のフォーム(まあ、単数形)を設計した方法が間違っていると感じているので、その場合は、そのトピックを特定してカバーする回答も最も役立ちます!

これが私の基本フォームです(テストボタンは...テスト用です):
ユーザーフォームのデザインビューの一部

そして、これら3つのボタンのいずれかがクリックされると(ワークシートActiveXコマンドボタン)、以下のユーザーフォームのいずれかが入力されます(キャプションはボタンに対応します)。
ワークシートActiveXコマンドボタン

NECユーザーフォーム LGユーザーフォーム その他のユーザーフォーム

Now, my data validation works fine for the NEC and LG forms, but fails when it gets to the Other form. This is because one Product Type CheckBox is required for the NEC and LG products, but not for the Other products and the data validation fails if there is no Product Type.

Here I'll include the CommandButton1_Click (test button) event and the class module code. My data validation is done in the UserForm module but I was recently reading i should put it in the Model so I think I need to move it to the Module doing all the other things.

UserForm Code Module - 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

Class Module - 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

So, more specifically;

The problem lies with DataEntryForm.TestProduct. It is within the IsFormCompleted function as 2/3 forms require this property to have a value, but naturally isn't required for the form without any Product Types.

My thoughts are the easy fix is to create another separate form for the Other Products version which can have a separate data validation function, but I want to try keep maintainability and avoid having more than 1 of this form.

How can I have this type of data validation adapt to recognise if the control should have a value or not?

Mathieu Guindon

Your model class being named *Form got me confused for a minute; I might have named the form like that (or TestView) and used TestModel for the model class :)

If the role of the view/form is to present the data, the role of the model is to, well, be the data. TestProduct is one such piece of data: its validity is also presentable data. You could consider this metadata and go wild and have a some TestModelValidator class implementing some IModelValidator interface that might look like this:

Public Function IsValid() As Boolean
End Function

...but that's probably overkill. If we're good with having the model responsible for both the data and its validation, then the model class could look like this:

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

Now the view can manipulate the model - not what's happening here:

Private Sub CommandButton1_Click()

With Me
    If .CheckBox1.Value = True Then
        DataEntryForm.TestProduct = .CheckBox1.Caption
    ElseIf .CheckBox2.Value = True Then
        DataEntryForm.TestProduct = .CheckBox2.Caption

Instead of querying the UI, listen in when the UI tells you what's going on - handle each control's Change event, and then let the model drive the state of the 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

Hope it helps!


編集/補遺:モデルの状態を使用して、そのようなコントロールを表示するかどうかも決定します。モデルクラスは、可能な限り多くのロジックをカプセル化する必要があります(フォームのコードビハインドに含めるのとは異なります)。これにより、すべてのエッジケースを手動でテストしなくても、モデルクラスに対してその動作を検証および文書化するテストを簡単に作成できます。何かを壊す可能性のある変更を加えるたびに、実際の形で!言い換えると、コンボボックスにデータを入力したり、チェックボックスコントロールをできるだけ多く作成したりするために、ビュー/フォームにサプライヤ名のコレクションが必要な場合、このデータをカプセル化するのはモデルの仕事です。

つまり、モデルロジックの一部を駆動するためにフラグが必要な場合は、そのフラグをモデルの状態の一部にします。

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

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

ユーザーが入力を入力した場合、否定または空の入力ボックスをチェックしてアラートメッセージをスローするフォームがあります

分類Dev

ループを使用してExcelユーザーフォームのエントリを検証しますか?

分類Dev

Javascriptがフォームを正しく検証していません。ユーザー入力なしでアラートが表示される

分類Dev

Angular 5で事前入力されたデータを使用してフォームコントロールを検証する方法は?

分類Dev

表示ダイアログでテキストフォームを使用してユーザー入力を取得する方法をフラッターしますか?

分類Dev

ユーザーがグーグルクロームの自動入力オプションでフォームに入力するかどうかを検出します

分類Dev

Purescriptハロゲンは、フォームの外部で入力検証を手動でトリガーします

分類Dev

Kenticoカスタムフォームコントロールタイプ:ユーザーに特殊文字を入力して検索させたい

分類Dev

ユーザーコントロールの入力値を検証する

分類Dev

c#(Windowsフォーム)を使用して、Designerからカスタムユーザーコントロール内のコントロールプロパティにアクセスする方法はありますか?

分類Dev

モデル駆動型アプローチなしでテンプレート駆動型フォームを検証する方法。

分類Dev

ユーザーコントロールのlinklabelを使用して、値をフォームに渡します

分類Dev

Javaユーザーがコマンドプロンプトに入力を入力するまでプログラムの実行を停止します

分類Dev

フォームを無効にしても、チャイルドコントロールは入力を受け取ることができます

分類Dev

別のユーザーコントロールが使用されている場合にのみ、コントロールを検証します

分類Dev

ユーザーがフォームに入力している間にファイルをアップロードする

分類Dev

ユーザーがフォームに入力している間にファイルをアップロードする

分類Dev

Vuelidateを使用して、親コンポーネントの子コンポーネントのフォーム入力フィールドを検証します

分類Dev

ユーザーがHTMLフォームを使用してファイルをアップロードしていることをjQueryで検証するにはどうすればよいですか?

分類Dev

フォームコントロールを介してinputtype = timeでフィールドを検証する方法は?使用済みAngularマテリアル

分類Dev

ユーザーフォームのコントロールをループして、特定のコントロールを非表示にします

分類Dev

ログインしたユーザーのユーザー名をdjangoフォームフィールドにラベルとして入力します

分類Dev

コントローラを使用してフォローしていないユーザーのリストをプルアップする(Rails)

分類Dev

try-exceptブロックを使用して入力を検証し、whileステートメントを使用してPythonで有効な入力が行われるまでユーザーにプロンプトを表示するにはどうすればよいですか?

分類Dev

Perlでユーザー入力を使用してローカルプログラムを実行する方法

分類Dev

Django:AJAXを使用したファイルのアップロード:フォームに、ファイル入力フィールドが空である(またはCSRFトークンがないか正しくない)と表示されます

分類Dev

グループ内のコントロールの1つに値がある場合、Angular 2フォームで単純なクロスフィールド検証を実行して検証に合格する方法は?

分類Dev

Safariを使用しているときに、オートコンプリートがプロモーションコードフィールドにユーザーの住所を入力するのはなぜですか?

分類Dev

再帰を使用してコードをループするにはどうすればよいですか(ユーザーが無効な入力を入力すると、再度プロンプトが表示されます)?

Related 関連記事

  1. 1

    ユーザーが入力を入力した場合、否定または空の入力ボックスをチェックしてアラートメッセージをスローするフォームがあります

  2. 2

    ループを使用してExcelユーザーフォームのエントリを検証しますか?

  3. 3

    Javascriptがフォームを正しく検証していません。ユーザー入力なしでアラートが表示される

  4. 4

    Angular 5で事前入力されたデータを使用してフォームコントロールを検証する方法は?

  5. 5

    表示ダイアログでテキストフォームを使用してユーザー入力を取得する方法をフラッターしますか?

  6. 6

    ユーザーがグーグルクロームの自動入力オプションでフォームに入力するかどうかを検出します

  7. 7

    Purescriptハロゲンは、フォームの外部で入力検証を手動でトリガーします

  8. 8

    Kenticoカスタムフォームコントロールタイプ:ユーザーに特殊文字を入力して検索させたい

  9. 9

    ユーザーコントロールの入力値を検証する

  10. 10

    c#(Windowsフォーム)を使用して、Designerからカスタムユーザーコントロール内のコントロールプロパティにアクセスする方法はありますか?

  11. 11

    モデル駆動型アプローチなしでテンプレート駆動型フォームを検証する方法。

  12. 12

    ユーザーコントロールのlinklabelを使用して、値をフォームに渡します

  13. 13

    Javaユーザーがコマンドプロンプトに入力を入力するまでプログラムの実行を停止します

  14. 14

    フォームを無効にしても、チャイルドコントロールは入力を受け取ることができます

  15. 15

    別のユーザーコントロールが使用されている場合にのみ、コントロールを検証します

  16. 16

    ユーザーがフォームに入力している間にファイルをアップロードする

  17. 17

    ユーザーがフォームに入力している間にファイルをアップロードする

  18. 18

    Vuelidateを使用して、親コンポーネントの子コンポーネントのフォーム入力フィールドを検証します

  19. 19

    ユーザーがHTMLフォームを使用してファイルをアップロードしていることをjQueryで検証するにはどうすればよいですか?

  20. 20

    フォームコントロールを介してinputtype = timeでフィールドを検証する方法は?使用済みAngularマテリアル

  21. 21

    ユーザーフォームのコントロールをループして、特定のコントロールを非表示にします

  22. 22

    ログインしたユーザーのユーザー名をdjangoフォームフィールドにラベルとして入力します

  23. 23

    コントローラを使用してフォローしていないユーザーのリストをプルアップする(Rails)

  24. 24

    try-exceptブロックを使用して入力を検証し、whileステートメントを使用してPythonで有効な入力が行われるまでユーザーにプロンプトを表示するにはどうすればよいですか?

  25. 25

    Perlでユーザー入力を使用してローカルプログラムを実行する方法

  26. 26

    Django:AJAXを使用したファイルのアップロード:フォームに、ファイル入力フィールドが空である(またはCSRFトークンがないか正しくない)と表示されます

  27. 27

    グループ内のコントロールの1つに値がある場合、Angular 2フォームで単純なクロスフィールド検証を実行して検証に合格する方法は?

  28. 28

    Safariを使用しているときに、オートコンプリートがプロモーションコードフィールドにユーザーの住所を入力するのはなぜですか?

  29. 29

    再帰を使用してコードをループするにはどうすればよいですか(ユーザーが無効な入力を入力すると、再度プロンプトが表示されます)?

ホットタグ

アーカイブ