Использовать / подписывать пользовательские события модуля класса - PullRequest
2 голосов
/ 10 мая 2019

Я хочу использовать событие из написанного мною модуля класса. Модуль класса выглядит следующим образом

''CError64Row
Public Event ErrorClicked(ByVal row As Integer, ByVal column As Integer)

Public WithEvents lblDescription As MSForms.Label
Public WithEvents lblFile As MSForms.Label
Public WithEvents lblRow As MSForms.Label
Public WithEvents lblCol As MSForms.Label

Public row As Long
Public col As Long

Private Sub lblDescription_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
   RaiseEvent ErrorClicked(row, col)
End Sub

Private Sub lblFile_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
   RaiseEvent ErrorClicked(row, col)
End Sub

Private Sub lblRow_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
   RaiseEvent ErrorClicked(row, col)
End Sub

Private Sub lblCol_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
   RaiseEvent ErrorClicked(row, col)
End Sub

В одной из моих форм я создаю CError64Row объекты

Private m_Elements As Long

Private mErrors() As CError64Row

Private Sub UserForm_Initialize()
    m_Elements = 0
End Sub

Public Function SetError(text As String, filename As String, row As Integer, column As Integer) As String
    Dim ctl As control

   ReDim Preserve mErrors(m_Elements + 1)

    Dim errorRow As CError64Row
    Set errorRow = New CError64Row
    Set mErrors(m_Elements) = errorRow

    mErrors(m_Elements).row = row
    mErrors(m_Elements).col = column
    Set mErrors(m_Elements).lblDescription = Me.Controls.Add("forms.label.1")
    With mErrors(m_Elements).lblDescription
        .Left = 35
        .height = 14
        .Top = 18 + (m_Elements) * 14
        .width = 631
        .Caption = text
    End With

    Set mErrors(m_Elements).lblFile = Me.Controls.Add("forms.label.1")
    With mErrors(m_Elements).lblFile
        .Left = 665
        .height = 14
        .Top = 18 + (m_Elements) * 14
        .width = 106
        .Caption = filename
    End With

    Set mErrors(m_Elements).lblRow = Me.Controls.Add("forms.label.1")
    With mErrors(m_Elements).lblRow
        .Left = 770
        .height = 14
        .Top = 18 + (m_Elements) * 14
        .width = 36
        .Caption = CStr(row)
    End With

    Set mErrors(m_Elements).lblCol = Me.Controls.Add("forms.label.1")
    With mErrors(m_Elements).lblCol
        .Left = 805
        .height = 14
        .Top = 18 + (m_Elements) * 14
        .width = 36
        .Caption = CStr(column)
    End With
    m_Elements = m_Elements + 1
End Function

Public Sub CError64Row_ErrorClicked(ByVal row As Integer, ByVal column As Integer)
    MsgBox "MSG received"
End Sub

Я хочу получить событие ErrorClicked, но я не уверен, как подписаться на событие. Я прочитал в этом ответе Можно ли создавать и обрабатывать пользовательское событие в пользовательской форме? , на которое я могу "подписаться" через

Private Sub [Provider] _MemberName

но я сомневаюсь, что это работает с объектом, который создан в методе. Как я могу подписаться на событие объекта, который был создан в методе?

1 Ответ

3 голосов
/ 10 мая 2019
Private mErrors() As CError64Row

Ваши объекты «провайдера событий» находятся в этом массиве mErrors - вам нужно как-то объявить его WithEvents, но это будет недопустимо:

Private WithEvents mErrors() As CError64Row

Проблема не в том, что объект создается в методе - как он создается, не имеет значения. Проблема в том, что у вас нет возможности заставить форму обрабатывать события, перенаправляемые объектом, ссылка на который находится в массиве / коллекции, а не в поле Private WithEvents.

Решение состоит в том, чтобы заставить пользовательский класс общаться с формой - и у вас уже есть ссылка на него:

Private Sub lblDescription_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    Dim parentForm As TheFormClass
    Set parentForm = lblDescription.Parent
    parentForm.HandleErrorClicked(row, col)
End Sub

Теперь, это тесно связывает форму TheFormClass с классом пользовательского элемента управления, и это не идеально - что если нам нужно повторно использовать этот класс в другой форме?

Мы могли бы пойти с поздним связыванием:

Private Sub lblDescription_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    Dim parentForm As Object
    Set parentForm = lblDescription.Parent
    parentForm.HandleErrorClicked(row, col)
End Sub

Но тогда мы теряем проверку во время компиляции, и нет никакой гарантии, что у parentForm есть метод HandleErrorClicked - а если метода нет, мы взорвемся с ошибкой 438.

Если только ... если мы не формализуем это с помощью интерфейса, например очень простого IErrorView класса, который может выглядеть следующим образом:

Option Explicit
Public Sub HandleErrorClicked(ByVal row As Long, ByVal col As Long)
End Sub

... и заставить класс формы реализовать этот интерфейс:

Implements IErrorView

Private Sub IErrorView_HandleErrorClicked(ByVal row As Long, ByVal col As Long)
    ' there's the handler!
End Sub

И теперь пользовательский класс управления может работать с любой формой, которая реализует интерфейс IErrorView, и мы получаем подтверждение во время компиляции:

Private Sub lblDescription_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    Dim parentForm As IErrorView
    Set parentForm = lblDescription.Parent
    parentForm.HandleErrorClicked(row, col)
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...