powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / коллекция обьектов + перехватить Events
19 сообщений из 19, страница 1 из 1
коллекция обьектов + перехватить Events
    #33932766
miki1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть контроль ocx который является контейнером для других ocx -ов

Есть коллекция обьектов с withEvents 2 класса
один сама коллекция
другой обработка обьекта

на каждый ocx есть свой Event
как можно в контейнере (ocx) получить перехватить Event на каждый ocx
и обработать его
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33933010
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если я правильно понял формулировку, то надо в проект, в котором содержится класс-коллекция, добавить private класс-оболочку для "другого ocx"-а. Этот класс содержит член-ссылку на хозяина-коллекцию и WithEvents член-ссылку на "другой ocx". По приходу события "другого ocx"-а класс-оболочка вызывает Friend-метод коллекции, который и делает RaiseEvent. Во внутренней же коллекции хранятся ссылки на экземпляры класса-оболочки, но реализация public-методов коллекции это скрывает.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33933077
miki1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А как это реализовать для получения Event в родительском ocx который контейнер
как получить член-ссылку на хозяина-коллекцию
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33933198
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miki1,
уж больно косноязычное описание проблемы.

Поэтому приведу пример для ситуации, как я её понял.

Пусть есть некий класс, назовём его CMyItem, который умеет генерировать события. Он может лежать в другом .ocx-файле, быть написан другим человеком на другом языке и т. п. Например, код у этого класса такой:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Option Explicit

Public Event Changed(ByVal OldValue As Long, ByVal NewValue As Long)

Private m_lValue As Long

Public Property Get Value() As Long
 Value = m_lValue
End Property

Public Property Let Value(ByVal NewValue As Long)
 Dim OldValue As Long
 OldValue = m_lValue
 If OldValue <> NewValue Then
    m_lValue = NewValue
    RaiseEvent Changed(OldValue, NewValue)
 End If
End Property

Пусть есть класс, назовём его CMyItems, есть методы Count, Add, Remove, Item, реализующие функциональность коллекции элементов типа CMyItem. Это может быть отдельный класс, а может быть часть класса-контейнера. Код CMyItems:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
Option Explicit

Private m_Items As Collection 'внутренняя коллекция

Public Event ItemChanged(Item As CMyItem, ByVal OldValue As Long, ByVal NewValue As Long)

Private Sub Class_Initialize()
 Set m_Items = New Collection
End Sub

Private Sub Class_Terminate()
 Set m_Items = Nothing
End Sub

Public Function Count() As Long
 Count = m_Items.Count
End Function

Public Sub Add(Item As CMyItem, Optional Key, Optional Before, Optional After)
 'Добавляем во внутреннюю коллекцию новый экземпляр класса-оболочки
 Dim ItemNotifier As New CMyItemNotifier
 ItemNotifier.Init Me, Item
 m_Items.Add ItemNotifier, Key, Before, After
End Sub
 
Public Sub Remove(Index)
 m_Items.Remove Index
End Sub

Public Function Item(Index) As CMyItem
 Dim ItemNotifier As CMyItemNotifier
 'Вытаскиваем из ссылки на экземпляр класса-оболочки ссылку на элемент
 Set ItemNotifier = m_Items(Index)
 Set Item = ItemNotifier.Item
End Function

Friend Sub NotifyItemChanged(Item As CMyItem, ByVal OldValue As Long, ByVal NewValue As Long)
 'Friend-методы не видны за пределами проекта.
 'Передаём событие элемента наверх.
 RaiseEvent ItemChanged(Item, OldValue, NewValue)
End Sub

Тогда код класс-оболочка для CMyItem, назовём его CMyItemNotifier, выглядит так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
Option Explicit

Private m_Items As CMyItems 'ссылка на хозяина-коллекцию
Private WithEvents m_Item As CMyItem

Private Sub Class_Terminate()
 Set m_Item = Nothing
 Set m_Items = Nothing
End Sub

Private Sub m_Item_Changed(ByVal OldValue As Long, ByVal NewValue As Long)
 'Вызов Friend-метода хозяина, который, в свою очередь,
 'делает RaiseEvent, т.е. передаёт событие на более высокий уровень
 m_Items.NotifyItemChanged m_Item, OldValue, NewValue
End Sub

Friend Sub Init(Items As CMyItems, Item As CMyItem)
 Set m_Items = Items
 Set m_Item = Item
End Sub

Friend Property Get Item() As CMyItem
 Set Item = m_Item
End Property
Данный класс должен находиться в том же проекте, что и CMyItems, и иметь Instancing = 1 (Private).
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33934093
miki1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт Спасибо
похоже на то что нужно

только не понятно как использовать класс CMyItemNotifier
использовать WithEvnts с ним не получается

а насчёт косноязычного описания проблемы
я как Моника Ливински языком не владею
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33934465
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miki1,
CMyItemNotifier не генерирует события (нет в нём Public Event и RaiseEvent) - WithEvents в описании экземпляра не нужен. Это сугубо посреднический private класс, снаружи проекта его и не видно. Его единственное предназначение - быть задействованным в CMyItems как класс, экземпляры которого будут складываться во внутреннюю коллекцию класса-контейнера.

Если же CMyItem и CMyItems лежат в одной библиотеке (проекте), то функциональность CMyItemNotifier можно засунуть в CMyItem и отказаться от CMyItemNotifier.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33934871
miki1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт Спасибо
я просто не то скопировал

Вопрос другой если можно

если я ставлю этот контейнер на форму и добавляю контроли во внутрь
то события на контроли внутри срабатывают в основой форме

но если добавление контейнера динамическое через Controls.Add
то событие на контроли внутри не срабатывает в основной форме
все RaiseEvent срабатывает по всем этапам
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33935358
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
miki1,
по динамическому добавлению ActiveX-ов на форму есть обязательная к прочтению статья: Q190670. How To Dynamically Add Controls to a Form with Visual Basic 6.0 . Поскольку в данном случае ActiveX свой, вопросы лицензирования можно игнорировать.
Если количество ActiveX-ов (контейнеров) заранее неизвестно, то придётся городить такой же огород с коллекцией, но на более высоком уровне - в роли CMyItem будет выступать уже контейнер.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #33935438
miki1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Бенедикт
огромное пионерское спасибо

Перезарегистрировал ocx и заработало

Хотя на событие каждого контроля нужно писать отдельный код
нет динамики

но всё равно спасибо

тема закрыта
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34243668
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Update:
взглянув трезвым послепраздничным взглядом, вижу, что есть ошибка при работе с памятью. Надо добавить в CMyItems метод
Код: plaintext
1.
2.
Public Sub Release()
 Set m_Items = Nothing
End Sub
, и вызывать его перед окончанием времени жизни переменной типа CMyItems.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34243683
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
..., либо циклом явно очищать CMyItems от элементов (вместо вызова Release).
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34243732
Фотография Worobjoff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Про работу без циклических ссылок я писал тут. Жаль нет времени написать хорошие примеры для повседневной работы.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34244064
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Worobjoff,
коллекция не управляет явно временем жизни экземпляра объекта (неявно управляет уничтожением - если ссылка на экземпляр, хранящаяся в ней, оказалась последней). Это означает что а) экземпляры могут (иногда, по логике, должны; пример: те же контролы, нарисованные в design-time, поэтому создаваемые автоматически) быть созданы/уничтожены извне коллекции; б) возможна реализация отношения "многие ко многим" между экземплярами и коллекциями. Пример в приведённой ссылке - не коллекция в этом (общепринятом? Microsoft-овском?) смысле, а некая фабрика классов, реализующая отношение "многие к одному". И, как мне показалось, Parent можно было бы реализовать прямее, через friend-свойство. Не всё ли равно, кому накручивать счётчик ссылок - экземпляру MyCollection, или её внутреннему свойству (m_Notifier; другой кандидат - mCol)?
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34244085
Фотография Worobjoff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да. я знаю про этот механизм подсчета ссылок.
А мой пример - лишь одну цель преследует: Чтобы после уничтожения ссылки на коллекцию, не пришлось принудительно гасить ссылки на входящие в нее объекты.
Сделал "Коллекция=Нафиг" - и все содержимое "нафингавалось" автоматически.
Кстати, контролы, которые надо анлоадить, вполне можно "гасить" (т.е. анлоадить) в событии Class_Terminate. И не придется специально уничтожать их. (на всякий случай уточню: анлоадить - не есть уничтожать ссылку).
В общем-то это - как раз и предусмотрено в COM. Т.е. чтобы этим пользовались (автоматическим сбором памяти без применения специальных методов).
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34244340
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Worobjoff,
да я не спорю, хороший пример к теории When to Use Events or Call-Backs for Notifications . (И трюки с ObjPtr/CopyMemory удовольствия действительно не доставляют).
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34244360
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
странное завершение старого топика.
2 Бенедикт

вероятно претензий к вашему первоначальному варианту кода не было,
по причине времени жизни контейнера равному времени жизни приложения.

недостаток предложенного Вами исправления в том, что оно вносит дополнительные условия на "правильное" использование контейнера.

автор(И трюки с ObjPtr/CopyMemory удовольствия действительно не доставляют).
В условиях данной конкретной задачи, когда по ее условиям:
- контейнер существует в отдельном компоненте,
- введенный Вами посредник CMyItemNotifier должен реализовываться приватным классом
- время жизни CMyItemNotifier не может быть больше времени жизни содержащего его контейнера
слабая ссылка абсолютно оправдана, не привносит опасностей использования и полностью развязывает ситуацию, исключая дополнительные соглашения по использованию контейнера.
вот код исправленного CMyItemNotifier, не вызывающего проблем с использованием контейнера.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
Option Explicit
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)

Const CClassName As String = "CMyItemNotifier"
Private m_Items As Long  'CMyItems 'ссылка на хозяина-коллекцию
Private WithEvents m_Item As CMyItem

Private Sub Class_Initialize()
    MsgBox "Класс: " & CClassName & VBA.vbNewLine & _
    "ObjPtr экземпляра:" & ObjPtr(Me), VBA.vbInformation + VBA.vbOKOnly, _
    "Создан экземпляр класса"
End Sub

Private Sub Class_Terminate()
 'Set m_Item = Nothing
 'Set m_Items = Nothing
  MsgBox "Класс: " & CClassName & VBA.vbNewLine & _
    "ObjPtr экземпляра:" & ObjPtr(Me), VBA.vbInformation + VBA.vbOKOnly, _
    "Уничтожен экземпляр класса"
End Sub

Private Sub m_Item_Changed(ByVal OldValue As Long, ByVal NewValue As Long)
 'Вызов Friend-метода хозяина, который, в свою очередь,
 'делает RaiseEvent, т.е. передаёт событие на более высокий уровень
 Dim parent As CMyItems
 If m_Items <>  0  Then
    Set parent = ObjFromPtr(m_Items)
    
    'm_Items.NotifyItemChanged m_Item, OldValue, NewValue
    parent.NotifyItemChanged m_Item, OldValue, NewValue
 End If
End Sub

Friend Sub Init(Items As CMyItems, Item As CMyItem)
 'Set m_Items = Items
 m_Items = ObjPtr(Items)
 Set m_Item = Item
End Sub

Friend Property Get Item() As CMyItem
 Set Item = m_Item
End Property

Private Function ObjFromPtr(ByVal Ptr As Long) As CMyItems
    Dim tmp As CMyItems
    CopyMemory tmp, Ptr,  4 
    Set ObjFromPtr = tmp
    CopyMemory tmp,  0 &,  4 
End Function

Какие в таком варианте для данной задачи (контейнер, живущий в собственном компоненте с приватным посредником) могут возникать неудовольствия, кроме сплошных удовольствий?



2 Worobjoff
Вы малек бредите в обсуждаемом вопросе.
авторЖаль нет времени ...
Попробуйте его найти. Вас же люди читают и даже разрешение на "использование" спрашивают.
распространение событий - один из механизмов вызова процедур.
Сам по себе он не решает и не может решать проблем циклических ссылок.
Я вполне к Вам с уважением. Надеюсь, совет "разобраться с вопросом" тоже будет встречен вполне доброжелательно.

(с выражением лица)
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34244941
Фотография Бенедикт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Victosha,
спасибо за код, но именно такого и хотелось бы избежать. Вопрос callbacks vs events и создания weak reference старый, активно обсуждался, например, в VBPJ (Visual Basic Programmer's Journal) в 1996-1998 годах (и подзабыт). Ваш "наезд" на Воробьёва мне не очень понятен (старый спор?). Пример (1 к 1 с его примером) могу привести я, если угодно .
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34245942
Фотография Victosha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ок.
Признаю - в своих эмоциях был неправ, погорячился. Данный пост прошу признать, как взятие эмоций взад и попытку сместить акценты.

Вступление в топик г-на Worobjoff я воспринял так, что здесь все неправильно написано, а "там" правильно. И упор на события делается как самостоятельное и самодостаточное средство, само по себе развязывающее циклические ссылки.
Существо дела не в событиях, а в конструкции и методе ее использования. Конструкция (почти) всегда определяется добавлением вспомогательного (почти всегда скрытого от непосредственного клиентского воздействия) объекта-посредника, полностью или частично развязывающего обратную связь. События – один из возможных механизмов передачи информации от развязывающего объекта к публикуемым классам связанной объектной модели.
Можно находить преимущества одного или другого способа в безопасности применения или эффективности реализации и даже спорить об этом. Возможно, лучше исходить из того, что могут быть различные реализации механизма управления набором связанных объектов, более или менее удачно подходящие для решения конкретной задачи. Важнее выявлять и понимать границы применения каждого из вариантов.
Внимательное повторное чтение дало мне основание думать, что г-н Worobjoff понимает это не хуже меня, и обращенные к нему слова я должен признать за ошибочные и забрать назад.

Если бы было: «а есть еще и такой подход», было бы в целом другое чтение.
Фактическое «про работу без циклических ссылок я писал тут» читается существенно иначе. Этим и определилась эмоциональная составляющая моего поста.

Странным образом в обоих случаях событийной передачи информации от посредника контейнеру находятся детали, затрудняющее чтение по диагонали и понимание прочитанного «влет».
В одном случае не объявлен mCol и о том, что это и как должна работать вся конструкция, приходится догадываться по косвенным признакам.

В другом - в классе Doofer свойство Parent заявлено как возвращающее Doofer, а должно быть Doofers.
“Совершенно понятно” что в обоих случаях это обычные опечатки. Но кусочек досады остается.
...
Рейтинг: 0 / 0
коллекция обьектов + перехватить Events
    #34246179
Фотография Worobjoff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На самом деле всегда есть несколько способов решения задачи.
Лично я препочитаю развязывать циклическую ссылку через события лишь потому что так она решается попутно с другой задачей.
Другая задача (их даже две) - это подписывание на события не только классом-коллекцией (специально не пишу "контейнером"). Ведь на события элемента коллекции может подписаться, например, форма отображающая ее в полях (или класс-биндинг) или другая коллекция (почему нет?). Но как передать события одного объекта сразу двум коллекциям? Ведь не будешь хранить ссылки на каждого владельца (упаси бог еще и коллекцию владельцев размещать в классе).
Вот и создаешь по два объекта при каждом Add - собственно элемент коллекции и транслятор событий. И держишь две коллекции в одном контейнерном классе. А еще вводишь поле-транслятор событий в классе-элементе коллекции (чтобы унифицировать всю работу с событиями. Наследования здесь нет, а для событий даже интерфейс не унаследуешь).
...А если писать отдельно код для передачи события контейнеру "владельцу" и генерацию события самим классом, получается дублирование кода...
... Ну это замечание уже устарело в связи с упомянутым чуть выше (не забываем, речь зашла о подавлени циклической ссылки).

Выложить классы это реализующие все это можно. Но сделать хорошее описание этому не нахожу времени.
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / коллекция обьектов + перехватить Events
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]