Userform - 从private sub返回public sub

时间:2017-09-27 15:55:51

标签: vba excel-vba userform excel

我有下面的代码,它是一个私有子,它是从一个公共子中的Userform3.show初始化的,据我所知,下面的代码可以工作,但是在完成时它不会返回到public sub。

请注意,当我更改sheet8.range(I16)的值时,会调用另一个私有子。但是我相信下面的代码就是问题所在。

有人可以建议我如何在完成后让私人子公司返回公共子公司吗?

Private Sub UserForm_Initialize()
'populate "Combo-Box with Boards

With Me.ComboBox1
.Clear ' clear previous items (not to have "doubles")
.AddItem "BISSB"
.AddItem "MORIB"
.AddItem "RMIB"
End With
End Sub
Private Sub CommandButton1_Click()

If Me.ComboBox1.ListIndex = -1 Then
UserForm3.Hide
MsgBox "No board was selected, please re-run macro and select appropriate board"
Exit Sub

Else
Sheet8.Range("I16").Value = ComboBox1.Text

End If
End Sub
Private Sub CommandButton2_Click()
UserForm3.Hide
MsgBox "No board was selected, please re-run macro and select appropriate board"
End
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
 If CloseMode = 0 Then
    MsgBox "No board was selected, please re-run macro and select appropriate board"
    End
    End If
End Sub

Public Sub

的开始
Sub newResumeAssessment_Click()
Dim answer As Variant
Dim Proceed As Boolean
Dim Uname As String

If UCase(Sheets("Main Menu").Range("A1")) = "YES" Then

answer = 6

Else

    answer = MsgBox("Click Yes to start a Business Case." & _
      vbCrLf & "Click No to resume the Business Case." & vbCrLf & _
      "Click Cancel to go back to the main menu." & vbNewLine & _
      vbNewLine & "Please note, you will need to load the board submission " & _
      "tracker before you start a new business case.", 35, "Business Case")

End If

If answer = 6 Then

UserForm3.Show

2 个答案:

答案 0 :(得分:4)

第一件事,删除End,无处不在。 End是一个大的红色NUKE'EM ALL按钮,结束执行,然后 - 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成员合法?

首先,您为事物命名,并使CommandButton1OkButtonCommandButton2CancelButton - 或者其他 - 只是不是Button1和Button2。< / p>

我喜欢您隐藏表单实例,而不是使用Unload Me进行核心操作,但是显式正在使用默认值实例,这意味着上面的New UserForm3代码不会隐藏正在显示的同一个实例。当您打算使用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

然后在OK按钮的处理程序中实现“happy-path”逻辑:

Private Sub OkButton_Click()
    Me.Hide
End Sub

我会禁用“确定”按钮,直到用户进行选择 - 这样他们可以取消,x-out或进行有效选择!

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:

  • 删除End指令无论身在何处。
  • 请勿在{{1​​}}内引用UserForm3(请改用UserForm3)。
  • 每次使用新的Me实例。
  • 公开New成员以便访问调用代码,以抽象出调用者不需要关心的控件。
  • 不允许表单处于无效状态。

答案 1 :(得分:0)

除非您以非模态方式显示表单,否则开头代码会一直停止,直到表单关闭