1

I'm trying to raise events from a modeless userform. My starting point is this excellent example. When I show the form modeless, the code raising the event executes, but the event handler never runs (I don't get the expected MsgBox when the Cancel button is clicked.) When I show the form modal, the events are handled as desired, but the form is no longer modeless as desired.

The userform named FormWithEvents has an OKButton and a CancelButton; here's the code behind:

Option Explicit

Public Event FormConfirmed()
Public Event FormCancelled(ByRef Cancel As Boolean)

Private Function OnCancel() As Boolean
    Dim cancelCancellation As Boolean
    RaiseEvent FormCancelled(cancelCancellation)
    If Not cancelCancellation Then Me.Hide
    OnCancel = cancelCancellation
End Function

Private Sub CancelButton_Click()
    OnCancel
End Sub

Private Sub OKButton_Click()
    Me.Hide
    RaiseEvent FormConfirmed
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = Not OnCancel
    End If
End Sub

Here's the code for the Presenter class that shows the form:

Option Explicit
Private WithEvents myModelessForm As FormWithEvents

Public Sub Show()
    Set myModelessForm = New FormWithEvents
    ' COMMENT OUT ONE OF THE FOLLOWING TWO LINES TO TOGGLE MODELESS OR MODAL
    myModelessForm.Show vbModeless  ' Modeless, but events don't get handled (no msgbox on clicking cancel button)
    ' myModelessForm.Show vbModal     ' Events get handled, but no longer modal
End Sub

Private Sub myModelessForm_FormCancelled(Cancel As Boolean)
    ' Setting cancel to True will leave the form open
    Cancel = MsgBox("Cancel this operation?", vbYesNo + vbExclamation) = vbNo
    If Not Cancel Then
        ' Modeless form was cancelled and is now hidden
        ' ...
        Set myModelessForm = Nothing
    End If
End Sub


Private Sub myModelessForm_FormConfirmed()
    ' Form was okayed and is now hidden
    Set myModelessForm = Nothing
End Sub

And here's the code in the main module:

Option Explicit

Public Sub RunForm()
    With New Presenter
        .Show
    End With
End Sub

Any ideas on where I've gone wrong?

xidgel
  • 3,085
  • 2
  • 13
  • 22

2 Answers2

1

Maybe this instead so you can keep your Presenter instance in scope:

Dim pres as Presenter

Public Sub RunForm()
    Set pres =  New Presenter
    pres.Show
End Sub
Tim Williams
  • 154,628
  • 8
  • 97
  • 125
0

Avoid using RaiseEvent. Declare a public instance of the Presenter class in the standard module. Option Explicit

Public Preter As New Presenter

Public Sub RunForm()

    With New Presenter
        .Show
    End With
End Sub

Convert the event procedure to a sub with public scope.

Sub FormCancelled(Cancel As Boolean)
    ' Setting cancel to True will leave the form open
    Cancel = MsgBox("Cancel this operation?", vbYesNo + vbExclamation) = vbNo
    If Not Cancel Then
        ' Modeless form was cancelled and is now hidden
        ' ...
        Set myModelessForm = Nothing
    End If
End Sub

The call the sub within the class.

Private Function OnCancel() As Boolean

    Dim cancelCancellation As Boolean

    Preter.FormCancelled cancelCancellation
    If Not cancelCancellation Then Me.Hide

    OnCancel = cancelCancellation
End Function

I'm not sure but your code line Set myModelessForm = Nothing in the class module bother me. I wonder whether the form should be hidden instead so that the code can continue to the Show procedure where the form can then be put to rest.

Variatus
  • 14,293
  • 2
  • 14
  • 30