第一件事, 消除End
,无处不在。End
是一个红色的“NUKE 'EM ALL”按钮ends立即执行,然后 - 之后End
已执行,无论您在调用堆栈中的位置如何,对于不再有调用堆栈;您的代码不再运行,无处可“返回”。
第二件事,不要将状态保留在默认实例的一种形式。像对待物体一样对待它,并且New
当您需要时创建一个新实例 - 这样您就不需要被打扰Unload
调用它和/或重置调用之间的状态:_Initialize
处理程序每次都会运行,并且不需要Clear
上次调用中的项目,因为您每次都将使用新的实例。你这样做:
With New UserForm3 'UserForm_Initialize handler runs here
.Show 'UserForm_Activate handler runs here
'anything after .Show will only run after the form is closed
If Not .Cancelled Then
Sheet8.Range("I16").Value = .ComboBox1.Text
End If
End With 'UserForm_Terminate handler runs here
请注意,工作表并未由表单写入 -这不是它的工作!那么我们如何做到这一点Cancelled
会员合法吗?
首先你命名事物和做CommandButton1
be OkButton
and CommandButton2
be CancelButton
- 或者其他什么 - 只是不是 Button1 和 Button2。
我喜欢你hiding表单实例而不是用核武器摧毁它Unload Me
,不管你是明确地工作关闭默认实例再次,这意味着上面New UserForm3
代码不会隐藏正在显示的同一实例。NEVER当您打算使用时,使用默认实例限定成员调用Me
.
换句话说:
UserForm3.Hide 'hides the default instance of UserForm3
Me.Hide 'hides whatever the current instance is
Hide 'same as Me.Hide
所以。添加一个Private isCancelled As Boolean
私有字段(模块级变量),然后公开一个Public Property Get Cancelled() As Boolean
返回它的公共属性 getter:
Option Explicit
Private isCancelled As Boolean
Public Property Get Cancelled() As Boolean
Cancelled = isCancelled
End Property
接下来,让您的取消按钮设置标志:
Private Sub CancelButton_Click()
isCancelled = True
Me.Hide
End Sub
然后使QueryClose
处理程序也设置它 - 并尽可能使用现有的命名常量:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
Cancel = True
isCancelled = True
Me.Hide
End If
End Sub
然后在“确定”按钮的处理程序中实现“happy-path”逻辑:
Private Sub OkButton_Click()
Me.Hide
End Sub
我会禁用“确定”按钮,直到用户做出选择 - 这样他们就可以取消、取消或做出有效的选择!
Public Property Get SelectedBoard() As String
SelectedBoard = IIf(Me.ComboBox1.ListIndex = -1, vbNullString, Me.ComboBox1.Text)
End Property
Private Sub ComboBox1_Change()
ValidateForm
End Sub
Private Sub ValidateForm()
Me.OkButton.Enabled = (SelectedBoard <> vbNullString)
End Sub
Private Sub UserForm_Activate()
ValidateForm
End Sub
现在调用者看起来像这样:
With New UserForm3
.Show
If Not .Cancelled Then
Sheet8.Range("I16").Value = .SelectedBoard
Else
MsgBox "No board was selected, please re-run macro and select appropriate board"
End If
End With
现在您有了一个窗体,它只不过是代码的 I/O 设备,正如它应该的那样。而且您使用的是对象而不是全局状态。
TL;DR:
- Remove
End
无论他们身在何处,都可以得到指导。
- 不参考
UserForm3
inside UserForm3
(use Me
反而)。
- 与新鲜人一起工作
New
每次都有实例。
- Expose
Property Get
供调用代码访问的成员,以抽象出调用者不需要关心的控件。
- 不允许表单处于无效状态。