Все очень просто. Так как события из простого модуля генерировать нельзя, то нужен глобальный объект для этих целей.
У меня таким объектом служит объект, единственный экземпляр которого порождается из класса CEventsDB (код класса ниже)
- Код: Выделить всё
'--------------------------------------------------------------------------------------------------------
' Module : CEventsDB
' Date : 14.11.2013
' Purpose : Класс для генерации глобальных событий обновления данных
'--------------------------------------------------------------------------------------------------------
Option Explicit
'{CEventsDB}
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'|Класс для генерации глобальных событий обновления данных из подсистемы уведомлений
'|Существует в единственном экземпляре (глобальная DAN ссылка), все объекты которым необходимы события
'|обновления должны иметь ссылку на этот объект с подпиской на события (WithEvents).
'|В подсистеме участвуют следующие классы:
'| CDataUpdate - Класс данных вносимых в коллекцию событий обновления полей рекордсетов
'| CEventHandlerRs - Класс обработчик событий рекордсета
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'[ПЕРЕМЕННЫЕ МОДУЛЯ]
'
Private m_Col As Collection
'[ДЕКЛАРАЦИЯ СОБЫТИЙ]
'
Event DataChanged(ByVal adReason As ADODB.EventReasonEnum, _
ByVal cRecords As Long, _
ByVal pRS As ADODB.Recordset, _
ByVal sTableName As String _
)
'
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + С В О Й С Т В А К Л А С С А +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + М Е Т О Д Ы К Л А С С А +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'Method [UpdateField] -
'**********************************************************************************************
Public Sub UpdateField(ByVal cFields As Long, _
ByVal Fields As Variant, _
ByVal pRS As ADODB.Recordset _
)
Dim oDU As CDataUpdate
Set oDU = New CDataUpdate
Set oDU.Field = Fields(0)
Set oDU.RS = pRS
Let oDU.Key = GetGUIDString
m_Col.Add oDU, oDU.Key
Set oDU = Nothing
End Sub
'Method [UpdateRecord] -
'**********************************************************************************************
Public Sub UpdateRecord(ByVal adReason As ADODB.EventReasonEnum, _
ByVal cRecords As Long, _
ByVal pRS As ADODB.Recordset _
)
Dim sTableName As String
Dim sBuff As String
Dim oDU As CDataUpdate
If adReason = adRsnUpdate Then
For Each oDU In m_Col
If oDU.RS Is pRS Then
sBuff = Nzs(oDU.Field.Properties("BASETABLENAME").Value)
If Len(sTableName) = 0 Then
sTableName = sBuff
Else
If sTableName <> sBuff Then
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RaiseEvent DataChanged(adReason, cRecords, pRS, sTableName)
sTableName = sBuff
End If
End If
m_Col.Remove oDU.Key
End If
Next
If Len(sTableName) <> 0 Then
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RaiseEvent DataChanged(adReason, cRecords, pRS, sTableName)
sTableName = vbNullString
End If
ElseIf adReason = adRsnDelete Then
sTableName = pRS!ID.Properties("BASETABLENAME").Value
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RaiseEvent DataChanged(adReason, cRecords, pRS, sTableName)
End If
End Sub
'Method [UpdateTable] -
'**********************************************************************************************
Public Sub UpdateTable(ByVal adReason As ADODB.EventReasonEnum, _
ByVal cRecords As Long, _
ByVal pRS As ADODB.Recordset, _
ByVal sTableName As String _
)
DoEvents
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
RaiseEvent DataChanged(adReason, cRecords, pRS, sTableName)
End Sub
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + О Б Р А Б О Т Ч К И С О Б Ы Т И Й +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'[Class_Initialize]
'********************************************************************************************************
Private Sub Class_Initialize()
Set m_Col = New Collection
End Sub
'[Class_Terminate]
'********************************************************************************************************
Private Sub Class_Terminate()
Set m_Col = Nothing
End Sub
Этот глобальный объект содержит коллекцию событий, элементами которой являются экземпляры класса CDataUpdate
- Код: Выделить всё
'--------------------------------------------------------------------------------------------------------
' Module : CDataUpdate
' Date : 14.11.2013
' Purpose : Класс 'Обновленные данные' для коллекции событий
'--------------------------------------------------------------------------------------------------------
Option Explicit
'{CDataUpdate}
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'|Класс с данными для коллекции событий обновления полей рекордсетов.
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + С В О Й С Т В А К Л А С С А +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'[ПУБЛИЧНЫЕ ПОЛЯ КЛАССА]
Public RS As ADODB.Recordset 'Ссылка на рекордсет, который обновился
Public Field As ADODB.Field 'Поле которое обновилось
Public Key As String 'Уникальный ключ на основе UUID
События порождаются в основном при манипуляциях с рекордсетами. Чтобы не плодить обработчики для каждого рекордсета я сделал отдельный класс обработчиков
- Код: Выделить всё
'--------------------------------------------------------------------------------------------------------
' Module : CEventHandlerRs
' Date : 14.11.2013
' Purpose : Класс 'Обработчик событий рекордсета'
'--------------------------------------------------------------------------------------------------------
Option Explicit
'{CEventHandlerRs}
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'|Класс обработчик событий рекордсета. Устанавливается ссылка на рекордсет с подпиской на события.
'|После связи с рекордсетом каждый экземпляр начинает обрабатывать все события обновления рекордсета
'|и взаимодействуя с глобальным объектом CEventsDB производит уведомления об обновлении данных.
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'[ПЕРЕМЕННЫЕ МОДУЛЯ]
Dim WithEvents m_RS As ADODB.Recordset
'
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + С В О Й С Т В А К Л А С С А +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'Property [Recordset] -
'********************************************************************************************* Read/Write
Public Property Get Recordset() As ADODB.Recordset
Set Recordset = m_RS
End Property
Public Property Set Recordset(oRS As ADODB.Recordset)
Set m_RS = oRS
End Property
'*********************************************************************************************
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + М Е Т О Д Ы К Л А С С А +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'////////////////////////////////////////////////////////////////////////////////////////////////////////
' + О Б Р А Б О Т Ч К И С О Б Ы Т И Й +
'////////////////////////////////////////////////////////////////////////////////////////////////////////
'[События рекордсета]
'[m_RS_EndOfRecordset]
'********************************************************************************************************
Private Sub m_RS_EndOfRecordset _
(ByRef fMoreData As Boolean, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_EndOfRecordset"
End Sub
'[m_RS_FetchComplete]
'********************************************************************************************************
Private Sub m_RS_FetchComplete _
(ByVal pError As ADODB.Error, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_FetchComplete"
End Sub
'[m_RS_FetchProgress]
'********************************************************************************************************
Private Sub m_RS_FetchProgress _
(ByVal Progress As Long, _
ByVal MaxProgress As Long, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_FetchProgress"
End Sub
'[m_RS_FieldChangeComplete]
'********************************************************************************************************
Private Sub m_RS_FieldChangeComplete _
(ByVal cFields As Long, _
ByVal Fields As Variant, _
ByVal pError As ADODB.Error, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_FieldChangeComplete"
If adStatus = adStatusOK Then
Call g_oCEventsDB.UpdateField(cFields, Fields, pRecordset)
End If
End Sub
'[m_RS_MoveComplete]
'********************************************************************************************************
Private Sub m_RS_MoveComplete _
(ByVal adReason As ADODB.EventReasonEnum, _
ByVal pError As ADODB.Error, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_MoveComplete"
End Sub
'[m_RS_RecordChangeComplete]
'********************************************************************************************************
Private Sub m_RS_RecordChangeComplete _
(ByVal adReason As ADODB.EventReasonEnum, _
ByVal cRecords As Long, _
ByVal pError As ADODB.Error, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
If adStatus = adStatusOK Then
Call g_oCEventsDB.UpdateRecord(adReason, cRecords, pRecordset)
End If
End Sub
'[m_RS_RecordsetChangeComplete]
'********************************************************************************************************
Private Sub m_RS_RecordsetChangeComplete _
(ByVal adReason As ADODB.EventReasonEnum, _
ByVal pError As ADODB.Error, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_RecordsetChangeComplete"
End Sub
'[m_RS_WillChangeField]
'********************************************************************************************************
Private Sub m_RS_WillChangeField _
(ByVal cFields As Long, _
ByVal Fields As Variant, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_WillChangeField"
End Sub
'[m_RS_WillChangeRecord]
'********************************************************************************************************
Private Sub m_RS_WillChangeRecord _
(ByVal adReason As ADODB.EventReasonEnum, _
ByVal cRecords As Long, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Call DbgRSEventMessage("RS_WillChangeRecord", adReason, cRecords, adStatus, pRecordset)
End Sub
'[m_RS_WillChangeRecordset]
'********************************************************************************************************
Private Sub m_RS_WillChangeRecordset _
(ByVal adReason As ADODB.EventReasonEnum, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_WillChangeRecordset"
End Sub
'[m_RS_WillMove]
'********************************************************************************************************
Private Sub m_RS_WillMove _
(ByVal adReason As ADODB.EventReasonEnum, _
ByRef adStatus As ADODB.EventStatusEnum, _
ByVal pRecordset As ADODB.Recordset _
)
' Debug.Print "m_RS_WillMove"
End Sub
'[События класса]
'[Class_Terminate]
'********************************************************************************************************
Private Sub Class_Terminate()
Set m_RS = Nothing
End Sub
Вот собственно и все система. Обработчик событий рекордсета обрабатывает соответствующие события и дергает методы глобального объекта уведомлений. А там где нужно ловить и обрабатывать эти события нужно установить ссылку на глобальный объект уведомлений и вставить соответствующие обработчики. Кроме этого у меня сам слой доступа к данным обособлен. И если где-то мне нужен рекордсет, то я его всегда получаю через функцию
NewRecordset, в которую передаются необходимые аргументы. По сути эта функция и ей подобные (а у меня их много таких) решает вопрос отсутствия нормального конструктора объектов в VB6. Так вот внутри этой функции на основании переданного текста запроса или команды порождается новый экземпляр рекордсета, устанавливаются его параметры, делается коннект к базе, подключается обработчик из подсистемы уведомлений, делается запрос и возвращается ссылка на готовый рекордсет с данными. Поэтому я не парюсь каждый раз с подпиской на события, любой полученный рекордсет уже к ней подключен и начинает рассылать уведомления.
Вот как то так.
Кстати если кто то сделал по другому, мне тоже бы интересно было знать, кто и что выдумал