Newsgroup: it.comp.lang.visual-basic
Titolo: Raise Event e chiamate da moduli

Ri-buon giorno,
ecomi qui con la seconda domanda del giorno....
Ho una classe che sarebbe lieta di alzare un evento al proprio client, ma
la faccenda e' coplicata e cerco di spiegarla nel migliore modo possibile.
La mia classe MyClass ha dichiarato un evento
Event Evento (Tipo as Byte)
La routine che alza questo evento, purtroppo, puo' essere chiamata
soltanto da un modulo .bas, perche' per "elaborare" le situazioni in cui
alzare l'evento, sono stato costretto a scrivere una funzione in un modulo
bas e passare questa funizione ad una DLL esterna con AddressOF.
Nel mio modulo .bas, allora, semplicemente ho pensato di chiamare la Sub
della classe che alza l'evento (dichiarata Publica) e sperare che tutto
funzionasse correttamente; nel far girare l'applicazione, effettivamente
la chiamata alla sub viene fatta, viene eseguito il metodo Raise Event, ma
nessuno e' in grado di ricevere questo evento.
Questo perche' (penso io, altrimenti correggetemi), l'unico modo per
chiamare da un modulo una sub di una classe, e' quella di dichiarare un
oggetto del tipo della classe stessa, quindi l'eventuale evento alzato,
verrebbe proprio da quest'ultimo oggetto creato, e nessuno sarebbe in
grado di intercettare l'evento stesso, dato che in un modulo non puo'
essere creato un oggetto WithEvent.. Giusto?
Se si, come posso fare per far felice la mia classe che ha proprio voglia
di alzare eventi per il mondo?
Grazie... Maurizio
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it


Spero di farmi capire con un esempio.
Supponi di avere 3 moduli: MyClass (la tua classe), il modulo .bas e il form (o
la classe) che deve ricevere gli eventi.
[MyClass]
Friend Sub RaiseEvento(...)
    ' Friend perché così non è visibile al di fuori del progetto
    RaiseEvent Evento(...)
End Sub
[Modulo bas con il callback]
Private mMyClassInstance As MyClass
Public Sub RegisterMyClass(oMyClass As MyClass)
    Set mMyClassInstance = oMyClass
End Sub
Public Sub UnregisterMyClass()
    Set mMyClassInstance = Nothing
End Sub
...
<routine callback>
    mMyClassInstance.RaiseEvento(...)
[Form o classe in cui devi ricevere gli eventi]
Private WithEvents oMyClass As MyClass
...
Private Sub oMyClass_Evento(...)
    ...
End Sub
Private Sub Form_Initialize() ' o Class_Initialize
    Set oMyClass = New MyClass
    RegisterMyClass oMyClass
End Sub
Private Sub Form_Terminate() ' o Class_Terminate
    Set oMyClass = Nothing
    UnregisterMyClass
End Sub
Il limite di questa soluzione è che permette ad 1 sola istanza di ricevere gli
eventi, ma può essere facilmente estesa usando (con cautela) una collection.
Bye
Raf
-----------------------------------------------------
Funk: cooler than the other side of the pillow.

 Spero di farmi capire con un esempio [...]
...
Anche io avevo pensato di passare alla funzione regisrata, l'oggetto di
cui io voglio intercettare l'evento per riferimento... l'oggetto resta lo
stesso e quindi posso chiamare la sub AlzaEvento da una parte ed
intercettare l'evento da un'altra.
Il problema e' duplice...
Come dici giustamente tu, risulta difficilino gestire piu' istanze dello
stesso oggetto (tenendo presente che l'obbiettivo sarebbe quello di
gestirne fino a 4 contemporaneamente). A dire il vero non avevo pensato
proprio alla collection, ma cmq. la vedo complicata.
Il secondo problema e' che, qualora decidessi di esportare tutto in una
ActiveX esterna, non saprei proprio come fare.
In effetti non mi dispiacerebbe poi poter esportare classe e relativo
modulo(infatti al momento ne ho due, uno generale ed uno dedicato a questa
classe)  in un ActiveX, da capire poi se DLL o EXE.


 questa classe)  in un ActiveX, da capire poi se DLL o EXE.
Bye


 In tal caso allora probabilmente dovresti ricorrere ad una classe "Factory"
[...]
...
Mmmm.. non ci ho capito una leguminosa :-)
cmq. ricordo di aver letto, in qualche pagina del mio libro di VB
preferito, qualche cosa sulle Factory.... provero' a capirci qualche cosa.
Grazie... Maurizio


 cosa. Grazie... Maurizio
In pratica è una classe pubblica che ha un metodo per creare un'istanza di
un'altra classe, consentendo maggiore controllo su di essa rispetto
all'istruzione New.


 all'istruzione New.
...
Mmm... pero' poi resta il problema del cavolo di modulo dove c'e' la
funzione di callback.
Questo modulo dovrebbe seguire la classe MyClass ed essere inglobato nella
stessa DLL (o EXE), e ritorna il problema di alzare un evento tramite una
Sub nella classe, chiamata dalla funzione di CB nel modulo.


 modulo.
La classe Factory gestisce ed incapsula la creazione delle istanze da parte dei
client, mantenendole ad esempio in una collection pubblica definita nel modulo
bas.
Così ogni istanza creata e *utilizzata dal client* è "catalogata" in questa
collection in base ad un qualche meccanismo di indicizzazione in modo che la
funzione CB possa farvi riferimento e chiamare il metodo (Friend) della classe
MyClass che si occupa a sua volta di chiamare RaiseEvent.
Es:
[Factory.cls]
Public Function CreateMyClass() As MyClass
Dim oMyClass As MyClass
    Set oMyClass = New MyClass    ' Impossibile da fare esternamente in quant
MyClass è Public not creatable
    oMyClass.Key = "K" & ObjPtr(oMyClass) ' Un modo per ottenere una chiave
univoca da usare nella collection
    ClassInstances.Add oMyClass, oMyClass.Key
    Set CreateMyClass = oMyClass
    Set oMyClass = Nothing
End Function
Public Sub DestroyMyClass(oMyClass As MyClass)
    Set ClassInstances(oMyClass.Key) = Nothing
    ClassInstances.Remove oMyClass.Key
    Set oMyClass = Nothing
End Sub
[Modulo.bas]
Sub Callback(...)
    ...
    ' Ricerca l'istanza giusta nella collection ClassInstances in base a qualche
criterio...
    Set oMyClass = FindMyClass(...)
    oMyClass.RaiseMyEvent(...)
    ...
End Sub
Spero che non ci siano troppe ca22ate, ho scritto di getto senza controllare...
Ciao
Raf

 client [...]
...
Interessante.
Naturalmente sarebbe possibile anche, nel client, creare un tot numero di
istanze della classe Factory, in modo da avere tot oggetti che fanno
riferimento ognuno ad una sola classe MyClass, cosi che se mi servono ad
esempio solo due riferimenti alla MyClass, io le creo tramite la factory e
intercetto gli eventi dall'oggetto objFactory1 e dall'oggetto objFactory2.
Or not? :-)


 dall'oggetto objFactory2. Or not? :-)
Non importa, della classe factory ne basta un'unica istanza. Anzi io la farei
addirittura Global Multiuse così non serve nemmeno crearla esplicitamente.
Sono le istanze della classe MyClass che essa restituisce ad essere diverse di
volta in volta.
Gli eventi li intercetta direttamente il form/la classe nel client.


 Gli eventi li intercetta direttamente il form/la classe nel client.
...
Si, ok, ma il client, da chi riceve eventi?
Mi spiego...
Abbiamo la Classe MyClass che e' la nostra beniamina gia' da un po', e poi
la classe MyFactory che e' quest'impiccio che stai suggerendo!
Il client immagino dovra' referenziare e creare una (o piu') istanza della
MyFactory. Cioe' Dim WithEvents objMyFactory as MyFactory
e poi Set objMyFactory = New MyFactory
quindi, per ricevere gli eventi da MyClass, e soprattutto sapere quale
delle classi ha alzato l'evento (intendo, quale istanza), bisognerebbe
implementare un metodo o una funzione nella MyFactory che vada a "capire"
chi delle istanze di MyClass ha voluto comunicare con il mondo.
Stesso discorso nel client... tramite un argomento dovrei essere in grado
di capire quale delle istanze di MyClass incluse nell'istanza MyFactory mi
ha sollevato l'evento.
Cosi' su due piedi (ma anche se mi rimetto seduto sulla sedia, non cambia
molto), mi sembrerebbe piu' semplice creare 4 oggetti diversi direttamente
da client e trattarli in maniera del tutto separata tra loro.
Se po' fa', vero?


 e poi Set objMyFactory = New MyFactory
Mi sa che ti stai complicando la vita.
Il client č in grado benissimo di ricevere gli eventi direttamente da MyClass,
esattamente come fosse una classe "interna" al progetto!
Supponendo di avere 1 solo form ad intercettare gli eventi:
Private WithEvents oMyClass As MyClass
Private oMyFactory As MyFactory    ' <- Superfluo se MyFactory la dichiari
Global Multiuse
Private Sub Form_Load()
    Set oMyFactory = New MyFactory
    Set oMyClass = oMyFactory.CreateMyClass()
End Sub
Ancora piů semplicemente, se MyFactory la dichiari Global Multiuse:
Private Sub Form_Load()
    Set oMyClass = CreateMyClass()
End Sub
Č sufficiente cosě.
Butta via il resto.
Mi auguro di averti chiarito le idee...


 End Sub
[...]> Mi auguro di averti chiarito le idee...
...
Caspita, si.
Incomincio ad avere qualche idea di cosa succede :-)
Provero', non so se questa settimana, ma provero'.
Grazie ancora... Maurizio
