VBA: головоломка WithEvents - PullRequest
       12

VBA: головоломка WithEvents

3 голосов
/ 23 марта 2011

У меня есть пользовательская форма, xForm , которая создается в модуле класса (скажем, TestClass ) как:

'TestClass
Dim Form as New xForm
Private WithEvents EvForm as MSForms.UserForm
Set EvForm = Form

В модуле класса самой xForm у меня есть код, который должен выполняться при закрытии формы, ТОЛЬКО если форма действительно закрывается:

'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

Событие QueryClose также обрабатывается в TestClass и может предотвратить закрытие формы:

'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

Как я могу проверить для Cancel = True, установленного в TestClass, в модуле класса xForm? Давайте перефразируем это: если Cancel имеет значение True в TestClass, я не должен делать код очистки в модуле класса xForm. Как мне это сделать?

До сих пор я думал о реализации другого события в классе xForm (My_QueryClose?) И вызывал его в событии QueryClose. Вне формы «Код позади» я буду иметь дело только с событием My_QueryClose, поэтому получаю полный контроль над происходящим. Это жизнеспособный / лучший подход?

Ответы [ 2 ]

1 голос
/ 25 марта 2011

Работа вокруг объявления другого события

Код ниже делает то, что я ожидал, хотя это не так аккуратно, как хотелось бы.

В UserForm1 код:

'***** 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

В Class1 код:

'***** 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

В базовом модуле ,для проверки класса:

'***** Basic module
Sub TestClass()
   Dim C As New Class1
   C.DoIt
End Sub

И вот конечный результат (окно отладки):

TestClass
Entered QueryClose
Cancel = -1
Status = QueryClose
Just before raising MyQueryClose
Just entered MyQueryClose
Just got back from MyQueryClose
Cancel = 0
Status = MY QueryClose
1 голос
/ 25 марта 2011

Невозможно придумать головы или хвосты вашей собственной идеи события, но способ заставить один класс общаться с другим (форма или что-то еще, не имеет значения), это связать их; Вот чистый пример:

Базовый TestClass содержит объект формы (здесь не нужно никаких событий, пусть форма обрабатывает это)

'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

Добавление пользовательского объекта и свойства к самой форме

'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

Вызов формы при создании TestClass выглядит следующим образом:

'TestClass code
Private Sub Class_Initialize()
    Set MyForm = New UserForm1
    Load MyForm
    Set MyForm.Parent = Me
End Sub

А затем, когда пришло время закрыть форму, вы проверяете, можете ли вы:

'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

Вот что он хотел бы вызвать

'standard module code
Public Sub Test_TestClass()
    Dim myclass As TestClass
    Set myclass = New TestClass
    myclass.MyFormProp.Show
End Sub
...