Запуск экземпляра UserForm
умолчанию для запуска шоу, пожалуй, самый простой способ, но он также является прямой причиной многих проблем - от простых, но трудно обнаруживаемых ошибок до проблем с обслуживанием и расширяемостью: "nice" & quick, works "решение - это шаблон" Smart UI ", который отлично работает для прототипа. Крупные проекты, которые постоянно растут с течением времени, требуют более умной архитектуры.
Программисты называют это «модель-представление-презентатор». Вид это форма. Данные - это модель, а затем есть презентатор, который координирует все это.
Вызов Sub Sheet из пользовательской формы
Правда в том, что вы этого не делаете. Модальная пользовательская UserForm
- это диалоговое окно, роль которого - не что иное, как сбор информации от пользователя. Делая его ответственным только за манипулирование данными, и оставляя макрос / вызывающую сторону ответственным за поток управления, вы делаете код более надежным и простым в обслуживании - особенно если форма может делать много вещей.
Начните с простого модуля класса MonthlyReportParams
:
Option Explicit
Public Month As Integer ' encapsulate into properties to implement
Public Year As Integer ' logic for validation on assignment.
Public Property Get IsValid() As Boolean
IsValid = Month >= 1 And Month <= 12 And _
Year >= 1900 And Year <= 2100
End Property
Теперь все, что нужно сделать пользовательской UserForm
- это работать с этими данными, с этой моделью.
Option Explicit
Private params As MonthlyReportParams
Private cancelled As Boolean
Private Sub Class_Initialize()
Set params = New MonthlyReportParams
End Sub
Public Property Get Model() As MonthlyReportParams
Set Model = params
End Property
Public Property Set Model(ByVal value As MonthlyReportParams)
Set params = value
MonthBox.value = params.Month
YearBox.value = params.Year
End Property
Public Property Get IsCancelled() As Boolean
IsCancelled = cancelled
End Property
Private Sub MonthBox_Change()
' make sure the textboxes contain numeric values before assigning to Integer
If IsNumeric(MonthBox.Value) Then params.Month = CInt(MonthBox.Value)
OnValidate
End Sub
Private Sub YearBox_Change()
' make sure the textboxes contain numeric values before assigning to Integer
If IsNumeric(YearBox.Value) Then params.Year = CInt(YearBox.Value)
OnValidate
End Sub
Private Sub OkButton_Click()
Me.Hide
End Sub
Private Sub CancelButton_Click()
OnCancel
End Sub
Private Sub OnCancel()
cancelled = True
Me.Hide
End Sub
Private Sub OnValidate()
OkButton.Enabled = Model.IsValid
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
' runs when form is just about to close
If CloseMode = VbQueryClose.vbFormControlMenu Then
' user clicked the [X] button
Cancel = True ' don't destroy the form
OnCancel
End If
End Sub
И теперь макрос, который вызывает эту форму, может вернуть контроль над происходящим: форма больше не запускает шоу, и мы можем прочитать все, что происходит, в одном месте:
Public Sub RunMonthlyReport(Optional ByVal targetSheet As Worksheet = Nothing)
If targetSheet Is Nothing Then
' no sheet was specified; work of the ActiveSheet
Debug.Assert Not ActiveSheet Is Nothing
Set targetSheet = ActiveSheet
End If
' create the model
Dim m As MonthlyReportParams
Set m = New MonthlyReportParams
m.Month = Month(Now)
m.Year = Year(Now)
' create the dialog, assign the model
With New MonthlyReportParamsDialog
Set .Model = m
.Show ' next line only runs after dialog has closed
If Not .IsCancelled Then
' run the report with the values in the model
targetSheet.Report m.Month, m.Year
End If
End With
End Sub
В этой статье можно найти дополнительную информацию о преимуществах такого "перестановки обязанностей", а также дополнительную логику обратного вызова в этой статье - отказ от ответственности: я написал оба; этот блог является официальным блогом для проекта OSS надстройки Rubberduck VBIDE, которым я владею.