Проверка данных в пользовательской форме не позволяет / \: *?"<> | для текстового поля - PullRequest
1 голос
/ 02 июля 2019

У меня есть пользовательская форма, которая при открытии файла «Мастер» переименовывает файл, как только вы заполните пользовательскую форму именем, которое происходит из имени события (текстовое поле «Пользовательская форма»).Проблема, которая у меня возникнет, заключается в том, что если кто-то использует 1 из 9 символов, которые вы не можете использовать, у меня есть обработчик ошибок, который не позволяет вам сохранять .... Я бы предпочел, чтобы они не могли продолжать работу в пользовательской форме доони правильно назвали свое событие.

Ниже приведена кнопка для отправки данных.Я думаю, что проверка должна быть включена в "Me.TextBoxE_EventName.Value" ... какие-либо идеи о том, что я мог бы вставить туда?

Private Sub CommandButton_ECancelREV_Click()

'----------------------------------------------------
'Check Validation of Completed form
'----------------------------------------------------
If Trim(Me.TextBoxE_RequestBy.Value) = "" Then
    Me.TextBoxE_RequestBy.SetFocus
    MsgBox "Please fill in 'Request By' before canceling form", vbCritical
        Exit Sub
End If

If Trim(Me.TextBoxE_OnSiteContact.Value) = "" Then
    Me.TextBoxE_OnSiteContact.SetFocus
    MsgBox "Please fill in 'On Site Contact' before canceling form", vbCritical
        Exit Sub
End If

If Trim(Me.TextBoxE_OnSiteNumber.Value) = "" Then
    Me.TextBoxE_OnSiteNumber.SetFocus
    MsgBox "Please fill in 'On Site Phone Number' before canceling form"
    Exit Sub
End If

If Trim(Me.TextBoxE_EventName.Value) = "" Then
    Me.TextBoxE_EventName.SetFocus
    MsgBox "Please fill in 'Event Name' before canceling form"
    Exit Sub
End If

If Trim(Me.ComboBoxE_LocationNumber.ListIndex) = -1 Then
  Me.ComboBoxE_LocationNumber.SetFocus
  MsgBox "Please fill in 'Location Number' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_OffSiteDelivery.ListIndex) = -1 Then
  Me.ListBoxE_OffSiteDelivery.SetFocus
  MsgBox "Please fill in 'Off Site Delivery?' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_RequestStatus.ListIndex) = -1 Then
  Me.ListBoxE_RequestStatus.SetFocus
  MsgBox "Please fill in 'Request Status' before canceling form"
  Exit Sub
End If

If Trim(Me.TextBoxE_DeliverDate.Value) = "" Then
  Me.TextBoxE_DeliverDate.SetFocus
  MsgBox "Please fill in 'Delivery Date' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_DeliverTime.ListIndex) = -1 Then
  Me.ListBoxE_DeliverTime.SetFocus
  MsgBox "Please fill in 'Delivery Time' before canceling form"
  Exit Sub
End If

If Trim(Me.TextBoxE_SSDate.Value) = "" Then
  Me.TextBoxE_SSDate.SetFocus
  MsgBox "Please fill in 'Show Start Date' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_SSTime.ListIndex) = -1 Then
  Me.ListBoxE_SSTime.SetFocus
  MsgBox "Please fill in 'Show Start Time' before canceling form"
  Exit Sub
End If

If Trim(Me.TextBoxE_SEDate.Value) = "" Then
  Me.TextBoxE_SEDate.SetFocus
  MsgBox "Please fill in 'Show End Date' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_SETime.ListIndex) = -1 Then
  Me.ListBoxE_SETime.SetFocus
  MsgBox "Please fill in 'Show End Time' before canceling form"
  Exit Sub
End If

If Trim(Me.TextBoxE_PickupDate.Value) = "" Then
  Me.TextBoxE_PickupDate.SetFocus
  MsgBox "Please fill in 'Pickup Date' before canceling form"
  Exit Sub
End If

If Trim(Me.ListBoxE_PickupTime.ListIndex) = -1 Then
  Me.ListBoxE_PickupTime.SetFocus
  MsgBox "Please fill in 'Pickup Time' before canceling form"
  Exit Sub
End If

    Me.Hide
    ThisWorkbook.Sheets("Equipment Request").Visible = True
    ThisWorkbook.Sheets("Equipment Request").Select

End Sub

Private Sub E_EnterInformation_Click()

'----------------------------------------------------
'Check Validation of Completed form
'----------------------------------------------------
If Trim(Me.TextBoxE_RequestBy.Value) = "" Then
    Me.TextBoxE_RequestBy.SetFocus
    MsgBox "Please fill in 'Request By' on form", vbCritical
        Exit Sub
End If

If Trim(Me.TextBoxE_OnSiteContact.Value) = "" Then
    Me.TextBoxE_OnSiteContact.SetFocus
    MsgBox "Please fill in 'On Site Contact' on form", vbCritical
        Exit Sub
End If

If Trim(Me.TextBoxE_OnSiteNumber.Value) = "" Then
    Me.TextBoxE_OnSiteNumber.SetFocus
    MsgBox "Please fill in 'On Site Phone Number' on form"
    Exit Sub
End If

If Trim(Me.TextBoxE_EventName.Value) = "" Then
    Me.TextBoxE_EventName.SetFocus
    MsgBox "Please fill in 'Event Name' on form"
    Exit Sub
End If

If Trim(Me.ComboBoxE_LocationNumber.ListIndex) = -1 Then
  Me.ComboBoxE_LocationNumber.SetFocus
  MsgBox "Please fill in 'Location Number' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_OffSiteDelivery.ListIndex) = -1 Then
  Me.ListBoxE_OffSiteDelivery.SetFocus
  MsgBox "Please fill in 'Off Site Delivery?' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_RequestStatus.ListIndex) = -1 Then
  Me.ListBoxE_RequestStatus.SetFocus
  MsgBox "Please fill in 'Request Status' on form"
  Exit Sub
End If

If Trim(Me.TextBoxE_DeliverDate.Value) = "" Then
  Me.TextBoxE_DeliverDate.SetFocus
  MsgBox "Please fill in 'Delivery Date' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_DeliverTime.ListIndex) = -1 Then
  Me.ListBoxE_DeliverTime.SetFocus
  MsgBox "Please fill in 'Delivery Time' on form"
  Exit Sub
End If

If Trim(Me.TextBoxE_SSDate.Value) = "" Then
  Me.TextBoxE_SSDate.SetFocus
  MsgBox "Please fill in 'Show Start Date' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_SSTime.ListIndex) = -1 Then
  Me.ListBoxE_SSTime.SetFocus
  MsgBox "Please fill in 'Show Start Time' on form"
  Exit Sub
End If

If Trim(Me.TextBoxE_SEDate.Value) = "" Then
  Me.TextBoxE_SEDate.SetFocus
  MsgBox "Please fill in 'Show End Date' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_SETime.ListIndex) = -1 Then
  Me.ListBoxE_SETime.SetFocus
  MsgBox "Please fill in 'Show End Time' on form"
  Exit Sub
End If

If Trim(Me.TextBoxE_PickupDate.Value) = "" Then
  Me.TextBoxE_PickupDate.SetFocus
  MsgBox "Please fill in 'Pickup Date' on form"
  Exit Sub
End If

If Trim(Me.ListBoxE_PickupTime.ListIndex) = -1 Then
  Me.ListBoxE_PickupTime.SetFocus
  MsgBox "Please fill in 'Pickup Time' on form"
  Exit Sub
End If

'Hide or show offsite and order number boxes

If Me.ListBoxE_OffSiteDelivery.Value = "Yes" Then
    Me.LabelE_OffSiteAdd.Visible = True
    Me.TextBoxE_OffSiteAdd.Visible = True
    Else
    EquipmentRequest.LabelE_OffSiteAdd.Visible = False
    EquipmentRequest.TextBoxE_OffSiteAdd.Visible = False
    End If

If Me.ListBoxE_OffSiteDelivery.Value = "Yes" And Me.TextBoxE_OffSiteAdd.Value = "" Then
    Me.TextBoxE_OffSiteAdd.SetFocus
    MsgBox "Please fill in 'Enter Off Site Location Name and Address' on form"
  Exit Sub
End If

If Me.ListBoxE_RequestStatus.Value <> "New" Then
    EquipmentRequest.LabelE_OrderNum.Visible = True
    EquipmentRequest.TextBoxE_OrderNum.Visible = True
    Else
    EquipmentRequest.LabelE_OrderNum.Visible = False
    EquipmentRequest.TextBoxE_OrderNum.Visible = False
    End If

If Me.ListBoxE_RequestStatus.Value <> "New" And Me.TextBoxE_OrderNum.Value = "" Then
    Me.TextBoxE_OrderNum.SetFocus
    MsgBox "Please fill in 'Enter Order/Job #' on form"
  Exit Sub
End If


'--------------------------------------------
'Enter Data in Form
'--------------------------------------------
Call UnProtectAllWorksheets

Sheets("Equipment Request").Range("C6") = Me.TextBoxE_RequestBy.Value       'Name of Requester
Sheets("Equipment Request").Range("C7") = Me.TextBoxE_OnSiteContact.Value   'Name of Contact
Sheets("Equipment Request").Range("C8") = Me.TextBoxE_OnSiteNumber.Value    'Phone Number format
Sheets("Equipment Request").Range("F11") = Me.TextBoxE_Comments.Value       'Comments (not required)

Sheets("Equipment Request").Range("I6") = Me.TextBoxE_EventName.Value       'Name of Event
Sheets("Equipment Request").Range("P24") = Me.ComboBoxE_LocationNumber.Value 'Location Number
Sheets("Equipment Request").Range("I8") = Me.ListBoxE_OffSiteDelivery.Value 'Yes or No Selection
Sheets("Equipment Request").Range("I9") = Me.ListBoxE_RequestStatus.Value   'New or revision or cancel selection

Sheets("Equipment Request").Range("C9") = Me.TextBoxE_PWDate.Value          'Short Date Format
Sheets("Equipment Request").Range("D9") = Me.ListBoxE_PWTime.Value          'Time Format
Sheets("Equipment Request").Range("C10") = Me.TextBoxE_DeliverDate.Value    'Short Date Format
Sheets("Equipment Request").Range("D10") = Me.ListBoxE_DeliverTime.Value    'Time Format
Sheets("Equipment Request").Range("C11") = Me.TextBoxE_SSDate.Value         'Short Date Format
Sheets("Equipment Request").Range("D11") = Me.ListBoxE_SSTime.Value         'Time Format
Sheets("Equipment Request").Range("C12") = Me.TextBoxE_SEDate.Value         'Short Date Format
Sheets("Equipment Request").Range("D12") = Me.ListBoxE_SETime.Value         'Time Format
Sheets("Equipment Request").Range("C13") = Me.TextBoxE_PickupDate.Value     'Short Date Format
Sheets("Equipment Request").Range("D13") = Me.ListBoxE_PickupTime.Value     'Time Format

Sheets("Equipment Request").Range("K8") = Me.TextBoxE_OffSiteAdd.Value     'Address of Offsite
Sheets("Equipment Request").Range("M9") = Me.TextBoxE_OrderNum.Value     'Order/Job # if revision
Sheets("Equipment Request").Range("D5") = Me.TextBoxE_CCEmails.Value

Call ProtectAllWorksheets

Me.Hide

Call ESaveBook

If Sheets("Equipment Request").Range("I9") <> "New" And Sheets("Equipment Request").Range("I9") <> "Dates Revision" And Sheets("Equipment Request").Range("I9") <> "Cancellation Revision" Then

ThisWorkbook.Sheets("Revised Equipment Request").Visible = True
ThisWorkbook.Sheets("Revised Equipment Request").Select

Else
ThisWorkbook.Sheets("Equipment Request").Visible = True
ThisWorkbook.Sheets("Equipment Request").Select
End If

End Sub

Я думаю, что это должно быть вложенным оператором if, я простонужна помощь, где и, возможно, хороший способ сделать это.Мы будем благодарны за любую помощь.

Ниже приведен макрос "ESaveBook" с обработчиком ошибок:

Sub ESaveBook()
'----------------------------------------------------
'Save File to Hard Drive For First Time
'----------------------------------------------------

    'Call UnProtectAllWorksheets

    Application.DisplayAlerts = False

    Dim sFile As String
    Dim sPath As String
    Dim sPS As String

    sPS = Application.PathSeparator
    sPath = Environ("UserProfile") & sPS & "Documents" & sPS & "!ERF!" & sPS & Format(Sheets("Equipment Request").Range("C10").Value, "mm.dd.yy") & " - " & Format(Sheets("Equipment Request").Range("C13").Value, "mm.dd.yy") & " " & Sheets("Equipment Request").Range("I6").Value & sPS
    CreateDirectory sPath
    If Len(Dir(sPath, vbDirectory)) = 0 Then Exit Sub   'Couldn't create the path due to invalid or inaccessible location
    sFile = Sheets("Equipment Request").Range("I6").Value & " ERF SAVED " & " " & Format(Date, "mm.dd.yy") & " " & Sheets("Equipment Request").Range("I9").Value & ".xlsm"

    ActiveWorkbook.SaveAs Filename:=sPath & sFile, FileFormat:=52

    MsgBox ("This file has been saved at 'Documents\!ERF!\") & Format(Sheets("Equipment Request").Range("C10").Value, "mm.dd.yy") & " - " & Format(Sheets("Equipment Request").Range("C13").Value, "mm.dd.yy") & " " & Sheets("Equipment Request").Range("I6").Value & ("'.  The file name is '") & sFile & ("'.  Please do not move target location of file.")

    Application.DisplayAlerts = True

    'Call ProtectAllWorksheets

End Sub

Sub CreateDirectory(ByVal arg_sFolderpath As String)

    If Len(Dir(arg_sFolderpath, vbDirectory)) = 0 Then
        Dim sPS As String
        sPS = Application.PathSeparator

        Dim sBuildPath As String
        Dim vFolder As Variant
        For Each vFolder In Split(arg_sFolderpath, sPS)
            If Len(vFolder) > 0 Then
                If Len(sBuildPath) = 0 Then sBuildPath = vFolder Else sBuildPath = sBuildPath & sPS & vFolder
                If Len(Dir(sBuildPath, vbDirectory)) = 0 Then
                    On Error Resume Next
                    MkDir sBuildPath
                    On Error GoTo 0
                    If Len(Dir(sBuildPath, vbDirectory)) = 0 Then
                        MsgBox "[" & sBuildPath & "] is either invalid or unreachable.", , "Create Directory Error"
                        Exit Sub
                    End If
                End If
            End If
        Next vFolder
    End If

End Sub

Ответы [ 3 ]

2 голосов
/ 02 июля 2019

TL; DR:

Вам нужна функция, которая может проверить, содержит ли данная строка один из нескольких запрещенных символов.Один из способов сделать это состоит в том, чтобы определить строку, содержащую каждый из этих символов по одному разу, затем выполнить итерацию каждого символа в этой строке и проверить, содержит ли ввод этот символ - и выручить, как только мы узнаем, каков ответ:

Private Function IsValidPathPartString(ByVal value As String) As Boolean
'a string is valid if it contains no characters illegal in a path/file name
    Const illegalChars = "/\:*?""<>|"
    Dim i As Long
    For i = 1 To Len(illegalChars)
        If InStr(value, Mid$(illegalChars, i, 1)) > 0 Then
            Exit Function 'implicit: false
        End If
    Next
    IsValidPathPartString = True
End Function

Model-View-Presenter

Любой нетривиальный диалог без структуры быстро превращается в большую кучу спагетти-беспорядка - независимо от того, написан он новичками VBA с MSForms или C #профессионалы с WinForms или WPF (современные рамки пользовательского интерфейса).Проблема присуща самой природе программирования пользовательского интерфейса, и программисты VBA, незнакомые с объектно-ориентированным программированием, наиболее уязвимы перед ловушками «интеллектуального пользовательского интерфейса», когда форма запускает шоу и происходит все, что когда-либо должно происходить.через форму: никогда не поздно отучиться от этого.

Работа формы заключается в том, чтобы собирать пользовательские данные и представлять данные .Период, конец этого.Откуда приходят данные, которые он представляет, это не его дело.То, что происходит с данными, собранными после сбора, также не имеет отношения к делу.

«Умный интерфейс» - не единственный способ программирования пользовательского интерфейса.Когда что-то выходит за рамки тривиального - и ваша форма определенно входит в эту нетривиальную категорию, нам нужна гораздо более надежная структура, чтобы вещи быстро не вышли из-под контроля.

Вот, Модель-View-Presenter Шаблон пользовательского интерфейса, который очень хорошо работает с MSForms (и WinForms, если вы погрузитесь в .NET-land).

Model

Есть класс "модель", чейответственность заключается в определении данных, которыми будет манипулировать форма.Этот класс модели также может быть ответственным за знание того, являются ли данные, которые он инкапсулирует, допустимыми;в более сложных сценариях вы можете разделить валидацию на собственный набор объектов, но давайте сделаем все просто.Класс может выглядеть примерно так (обратите внимание на выделенную функцию, проверяющую, содержит ли строка недопустимые символы в именах путей / файлов):

'EquipmentRequestModel.cls
Option Explicit
Private ValidationErrors As Collection

Public RequestedBy As String
Public OnSiteContact As String
Public OnSiteNumber As String
Public EventName As String
Public LocationNumber As String
Public OffSiteDelivery As String
'...

Public Property Get IsValid() As Boolean
    Validate
    IsValid = ValidationErrors.Count = 0
End Property

Public Property Get ModelValidationErrors As Variant
    If ValidationErrors.Count = 0 Then Exit Property 'implicit vbEmpty
    ReDim errors(0 To ValidationErrors.Count - 1)
    Dim e As Long
    For e = 0 To ValidationErrors.Count - 1
        errors(e) = ValidationErrors(e + 1) 'collection indexing is 1-based
    Next
    ModelValidationErrors = errors
End Property

Private Sub Validate()
    Set ValidationErrors = New Collection
    If Not IsValidRequiredString(RequestedBy) Then OnMissingRequiredFieldError "RequestedBy"
    If Not IsValidRequiredString(OnSiteContact) Then OnMissingRequiredFieldError "OnSiteContact"
    If Not IsValidRequiredString(OnSiteNumber) Then OnMissingRequiredFieldError "OnSiteNumber"
    If Not IsValidRequiredString(EventName) Then OnMissingRequiredFieldError "EventName"
    If Not IsValidPathPartString(EventName) Then OnValidationError "Field [EventName] cannot contain characters: [/\:*?""<>|]."
    '...
End Sub

Private Function IsValidRequiredString(ByVal value As String) As Boolean
'a required string is valid if it's non-empty after stripping leading/trailing spaces
    IsValidRequiredString = Trim(value) <> vbNullString
End Function

Private Function IsValidPathPartString(ByVal value As String) As Boolean
'a string is valid if it contains no characters illegal in a path/file name
    Const illegalChars = "/\:*?""<>|"
    Dim i As Long
    For i = 1 To Len(illegalChars)
        If InStr(value, Mid$(illegalChars, i, 1)) > 0 Then
            Exit Function 'implicit: false
        End If
    Next
    IsValidPathPartString = True
End Function

Private Sub OnMissingRequiredFieldError(ByVal propertyName As String)
    OnValidationError "Required field [" & propertyName & "] is empty."
End Sub

Private Sub OnValidationError(ByVal message As String)
    ValidationErrors.Add message
End Sub

Более сложные проверки, условно зависящие от значения того или иного свойства, могут легкобыть реализованным там, и если представлению требуются дополнительные метаданные, чтобы контролировать, должно ли быть видно то или иное поле, модель может также предоставить для этого Boolean свойств.

Теперь вы можете иметь код, который читаетна листе и заполняет свойства экземпляра этого класса значениями ячеек, или вы можете иметь код, который считывает свойства класса и заполняет их ячейками листа - хотя такой код не относится к модели.

НоКак такой класс влияет на выделение кода формы?

Представление

Форма требует ссылки на модель, в самом начале.Что приятно в MSForms, так это то, что вы бесплатно получаете атрибут VB_PredeclaredId (его легко злоупотреблять , но это другое обсуждение), поэтому очень легко добавить фабричный метод Create именно это и делает:

'EquipmentRequestView.frm
Option Explicit
Private model As EquipmentRequestModel

Public Property Get EquipmentRequestModel() As EquipmentRequestModel
    Set EquipmentRequestModel = model
End Property

Public Property Set EquipmentRequestModel(ByVal value As EquipmentRequestModel)
    Set model = value
    LoadModelData
End Property

Public Function Create(ByVal viewModel As EquipmentRequestModel) As EquipmentRequestView
    Dim result As EquipmentRequestView
    Set result = New EquipmentRequestView
    Set result.EquipmentRequestModel = viewModel
    Set create = result
End Function

Private Sub LoadModelData()
'synchronize control values as per model
    Me.TextBoxE_RequestBy.Value = model.RequestBy
    Me.TextBoxE_OnSiteContact.Value = model.OnSiteContact
    '...
    ValidateForm
End Sub

Форма содержит несколько элементов управления, и все эти элементы управления могут реагировать на события.Поэтому мы обрабатываем событие Change этих элементов управления и соответствующим образом обновляем модель:

Private Sub TextBoxE_RequestBy_Change()
    model.RequestBy = Me.TextBoxE_RequestBy.Value
    ValidateForm
End Sub

Private Sub TextBoxE_OnSiteContact_Change()
    model.OnSiteContact = Me.TextBoxE_OnSiteContact.Value
    ValidateForm
End Sub

'...

Процедура ValidateForm, вызываемая из соответствующего обработчика каждого элемента управления, каждый пользовательский ввод вызывает модельПодлежит проверке:

Private Sub ValidateForm()
    Dim isValidForm As Boolean
    isValidForm = model.IsValid

    'command buttons are only enabled if form is valid
    Me.E_EnterInformation.Enabled = isValidForm
    Me.CommandButton_ECancelREV.Enabled =isValidForm

    'validation errors label is only visible with invalid data
    Me.ValidationErrorsLabel.Visible = Not isValidForm
    Me.ValidationErrorsLabel.Caption = Join(model.ModelValidationErrors, vbNewLine)
End Sub

Вы могли бы также иметь более детальные метаданные об ошибках валидации с более продуманным механизмом валидации данных.Например, вместо простых строк ошибкой проверки модели может быть сам по себе объект со свойствами ErrorMessage, ViewControlName и ModelPropertyName, которые облегчают прикрепление определенной ошибки проверки к конкретному элементу управления нанапример, если вы хотите выделить красным цветом нужное поле, сфокусировать его или переключить видимость симпатичного маленького красного значка «X» с сообщением vaildation в свойстве значка ControlToolTip - предел небаздесь.

Что касается формы / представления, то это все.Это будет обработчик Click для вашей кнопки E_EnterInformation:

Private Sub E_EnterInformation_Click()
    Me.Hide
End Sub

Единственное, чего не хватает, - это обработки события QueryClose, чтобы мы могли отследить, что пользователь хочет просто внести в залог.вне формы и притворяться, что они никогда не хотели поднимать его.

Так как же тогда данные формы попадают на лист?

Presenter

Другой класс должен нести ответственность за соединение точек: что-то где-то должно создать модель, инициализировать ее (при необходимости), создать форму / передать ей модель, а затем показать форму и определить, что делать с теперь действующей версией.данные модели.

'EquipmentRequestPresenter.cls
Option Explicit

Public Sub Run()
    Dim model As EquipmentRequestModel
    Set model = InitializeModel
    With EquipmentRequestView.Create(model)
        .Show
        'todo: handle a user-cancelled form?
        UpdateWorksheet model
    End With
End Sub

Private Function InitializeModel() As EquipmentRequestModel
    Dim model As EquipmentRequestModel
    Set model = New EquipmentRequestModel
    'note: should probably be "With EquipmentRequestSheet"
    With ActiveWorkbook.Worksheets("Equipment Request")
        model.RequestBy = .Range("C6").Value 'todo: name these ranges...
        model.OnSiteContact = .Range("C7").Value '...urgently...
        model.OnSiteNumber = .Range("C8").Value '...before someone inserts a row/column
        '...
    End With
    Set InitializeModel = model
End Function

Private Sub UpdateWorksheet(ByVal model As EquipmentRequestModel)
    'note: should probably be "With EquipmentRequestSheet"
    With ActiveWorkbook.Worksheets("Equipment Request")
        .Unprotect
        .Range("C6").Value = model.RequestBy
        .Range("C7").Value = model.OnSiteContact
        .Range("C8").Value = model.OnSiteNumber
        '...
        .Protect
    End With
End Sub

Обратите внимание, что это означает, что процедура ESaveBook теперь также может принимать параметр model и использовать model.DeliveryDate вместо Range("C10") - что делает ее на одно место меньше для беспокойствакогда нужно изменить шаблон листа и добавить строку вверху, или столбец смещает все эти координаты ячейки и по-королевски все портит.Использование .Range("DeliveryDate") уже защитит ваш код от этого: именованный диапазон становится слоем абстракции между вашим кодом и фактическими ячейками рабочего листа, так что фактические координаты абстрагируются.из кода, который больше не нуждается во всевозможных «зачем снова эта ячейка?»комментарии ... которые могут быть или не быть точными.

Также обратите внимание: PascalCase регистр в модуле и процедуре на простом английском языке, произносимые имена, нигде не подчеркивание, нет прикольных префиксов.Не уверен, в чем дело с E везде.

В любом случае, при такой настройке макрос, который в данный момент вызывает .Show в этой форме, теперь должен выглядеть следующим образом:

Public Sub MyMacro()
    With New EquipmentRequestPresenter
       .Run
    End With
End Sub

Заключительное примечание: все вышеперечисленное - это воздушный код, предоставленный для иллюстрации концепций;ничего из этого не было проверено.

1 голос
/ 03 июля 2019

Хотя @MathieuGuindon предоставил одну долгосрочную стратегию, у меня есть альтернативный подход к проверке.

По сути, вместо того, чтобы проверять факт, прежде всего, пользователь не допустит ошибку -« унция профилактики обычно лучше, чем фунт лечения ».

В вашей форме вы можете получить доступ ко многим обработчикам событий.Полезным является KeyPress.Для очень простого и грязного примера:

Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
 '/ \ : * ? " < > | 
    If KeyAscii = Asc("/") or KeyAscii = Asc("\") Then
        KeyAscii = 0 ' This tells the form to ignore that input
    End If
End Sub

Конечно, мы можем сделать это умнее:

Private Function IsBadCharacter(keyToCheck as MSForms.ReturnInteger) as Boolean
     '/ \ : * ? " < > |
    Select Case keyToCheck
        Case Asc("/"), Asc("\"), Asc(":"), Asc("*"), Asc("?"), Asc(""""), Asc("<"), Asc(">"), Asc("|")
            IsBadCharacter = True
        Case Else
            IsBadCharacter = False
    End Select
End Function

Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
 '/ \ : * ? " < > | 
    If IsBadCharacter(KeyAscii) Then
        KeyAscii = 0 ' This tells the form to ignore that input
    End If
End Sub

Альтернативный подход здесь - просто вернуть 0 или исправить значение KeyAscii.из IsBadCharacter, но логический подход позволяет вам реализовать другие методы обработки ошибок, если вы того пожелаете.

Это означает, что некоторые из ваших проверок проверки данных выполняются в представлении, а любая аналогичная проверка выполняется в модели.является избыточным в этом примере (но все равно будет необходимо, если вы будете использовать шаблон повторно).Тем не менее, простой пользовательский опыт всегда хорош!

0 голосов
/ 02 июля 2019

Функция INSTR должна быть полезной для вас вместе с SELECT CASE TRUE

 SELECT CASE True
      CASE InStr(1,yourStringtoSearchIn, StringYouwantTofind)>0
 END SELECT

протестировано с

Private Sub dero()
    Dim this$, that$
    this = "der|p"
    that = "|"
     Select Case True
          Case InStr(1, this, that) > 0
        Debug.Print ; "foudn it"
     End Select
End Sub
...