I have a UserForm, xForm, that is being instantiated in a class module (let’s say TestClass) as:
'TestClass Dim Form as New xForm Private WithEvents EvForm as MSForms.UserForm Set EvForm = Form
At the class module of the xForm itself I have some code that must be executed on Form Closing, ONLY if the form actually closes:
'xForm class module Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) 'Do some cleanup, otherwise the app would hang 'If not closing, don't cleanup anything, otherwise the app would hang End Sub
The QueryClose event is also treated in TestClass, and could avoid the form from closing:
'TestClass Private Sub EvForm_QueryClose(Cancel As Integer, CloseMode As Integer) 'Verify if closing is allowed based on User Control values Cancel = Not ClosingIsAllowed '<-- Pseudocode on the right side of "=" End Sub
How can I test for Cancel = True, set in TestClass, in the xForm class module?
Let’s rephrase it: If Cancel is set to True in TestClass, I must not do the cleanup code in the xForm class module. How can I accomplish that?
Until now, I have thought off of implementing another event in the xForm class (My_QueryClose?) and raise it on the QueryClose event. Outside the Code Behind Form I would deal only with the My_QueryClose event, so taking full control over what is happening. Is this a viable/better approach?
Can’t make heads or tails of your custom event idea, but the way to get one class to talk to another (form or anything else, doesn’t matter) is to link them up; here’s a clean example:
Basic TestClass holds form object (no events needed here, let the form handle that)
'TestClass code Private MyForm As UserForm Private mbleCanClose As Boolean Public Property Get CanClose() As Boolean CanClose = mbleCanClose End Property Public Property Let CanClose(pbleCanClose As Boolean) mbleCanClose = pbleCanClose End Property Public Property Get MyFormProp() As UserForm1 Set MyFormProp = MyForm End Property
Add a custom object and property to the form itself
'UserForm1 code Private mParent As TestClass Public Property Get Parent() As TestClass Set Parent = mParent End Property Public Property Set Parent(pParent As TestClass) Set mParent = pParent End Property
Invoking the form on TestClass creation looks like this:
'TestClass code Private Sub Class_Initialize() Set MyForm = New UserForm1 Load MyForm Set MyForm.Parent = Me End Sub
And then when it’s time to close the form, you check whether you can:
'UserForm1 code Public Function WillMyParentLetMeClose() As Boolean If Not (mParent Is Nothing) Then WillMyParentLetMeClose = mParent.CanClose End If End Function Private Sub CommandButton1_Click() If WillMyParentLetMeClose = True Then Unload Me End If End Sub
Here’s what it would like to invoke
'standard module code Public Sub Test_TestClass() Dim myclass As TestClass Set myclass = New TestClass myclass.MyFormProp.Show End Sub
A work around declaring another event
The code bellow do what I was expecting, although it is not as neat as I wish it could be.
In the UserForm1 code:
'***** UserForm1 Public Event MyQueryClose(ByRef Cancel As Integer, ByRef CloseMode As Integer, ByRef Status As String) Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer) Dim Status As String Cancel = True Status = "QueryClose" Debug.Print "Entered QueryClose" Debug.Print "Cancel = " & Cancel Debug.Print "Status = " & Status Debug.Print "Just before raising MyQueryClose" RaiseEvent MyQueryClose(Cancel, CloseMode, Status) Debug.Print "Just got back from MyQueryClose" Debug.Print "Cancel = " & Cancel Debug.Print "Status = " & Status End Sub
In the Class1 code:
'***** Class1 Dim UserForm As New UserForm1 Private WithEvents UF As UserForm1 Sub DoIt() Set UF = UserForm UserForm.Show End Sub Private Sub UF_MyQueryClose(Cancel As Integer, CloseMode As Integer, Status As String) Debug.Print "Just entered MyQueryClose" Cancel = False Status = "MY QueryClose" End Sub
In a basic module, to test the Class:
'***** Basic module Sub TestClass() Dim C As New Class1 C.DoIt End Sub
And here’s the end result (debug window):
TestClass Entered QueryClose Cancel = -1 Status = QueryClose Just before raising MyQueryClose Just entered MyQueryClose Just got back from MyQueryClose Cancel = 0 Status = MY QueryClose