Newsgroup: it.comp.lang.visual-basic
Titolo: Notifica eventi (un pò lunghino)

Ciao a tutti.
Sto incontrando alcuni problemi con la notifica degli eventi da una dll.
Ho una griglia che rappresenta un elenco di libri.
Facendo doppio click su un record, apro una maschera dalla quale posso
modificare i vari dati del mio libro (titolo, autore..).
Poichè volevo avvicinarmi alla OOP, ho deciso di realizzare una dll che
racchiudesse
tutte le maschere di inserimento e modifica dati, così da non dover
ricompilare e ridistribuire
l'intero progetto in caso di errori.
Vorrei fare una cosa del tipo: doppio click, si apre la maschera di
modifica, modifico un dato,
salvo, e automaticamente vedo nella griglia sotto la mia maschera (aperta in
modalita vbModal) il dato
che cambia, anche senza chiudere la maschera e tornare alla griglia.
Il problema è che, notificando gli eventi (istanziando il mio oggetto con
withevents), riesco nel mio intento, ma solo
finchè eseguo il mio programma tramite ide di vb (a runtime intendo).. e
questo non sempre (vedi sotto).
Se lo compilo, non notifica un tubo.
Vi posto parte del codice.
*******************************
Questo è il codice della mia Griglia Libri
*******************************
Option Explicit
Private WithEvents objInsMod As dll_cart_InsMod.InsMod
'Questa è la rutine che mi crea l'oggetto
Private Sub sChiamaModifica()
        Set objInsMod = New dll_cart_InsMod.InsMod
        objInsMod.LetAction = "Modificare"
        objInsMod.LetConnection = strConnessione
        objInsMod.LetID = CLng(grdLibri.Columns(GIDLIBRO).Value)
        objInsMod.fShowMask Mask.Libri, objInsMod
        Set objInsMod = Nothing
End Sub
'Questo è l'evento generato dalla mia dll
Private Sub objInsMod_eRefresh(lngIDRecord As Long, Azione As String)
    grdLibri.Visible = False
    datLibri.Refresh
    grdLibri.Visible = True
    datLibri.Recordset.Filter = strFilter
    If datLibri.Recordset.RecordCount > 0 Then
        Select Case Azione
            Case "Aggiungi", "Modifica"
                datLibri.Recordset.Find ("IDLibro = " & lngIDRecord)
            Case "Elimina"
                datLibri.Recordset.MoveFirst
        End Select
    End If
    txtDisplay.Text = Format(datLibri.Recordset.RecordCount,
"###,###,###,###0")
End Sub
Alla dll passo Mask.Libri che altro non è che un tipo Enum che serve a me
per gestire il tipo di
maschera che voglio aprire (Libri, Clienti...).
Inoltre le passo anche lo stesso oggetto che ho creato (poi capirete
perchè...)
*******************************
Questo è il parte del codice della dll_cart_InsMod
*******************************
Option Explicit
Public Event eRefresh(lngIDRecord As Long, Azione As String)
Public Property Let LetID(ByVal vNewValue As Long)
    lngID = vNewValue
End Property
Public Property Let LetAction(ByVal vNewValue As String)
    strAction = vNewValue
End Property
Public Property Let LetConnection(ByVal vNewValue As String)
    strConnessione = vNewValue
End Property
Public Sub fShowMask(lngMask As Long, ByVal vNewValue As
dll_cart_InsMod.InsMod)
    Set cnCartolibreria = New ADODB.Connection
    'L'oggetto qui sotto è dichiarato come public in un modulo bas con la
seguente istruzione
    'Public objMaskLoc As dll_cart_InsMod.InsMod
    Set objMaskLoc = vNewValue
    cnMiaConnessione.CursorLocation = adUseClient
    cnMiaConnessione.Open strConnessione
    Select Case lngMask
        Case Mask.CLIENTI
            Load MascheraClienti
            MascheraClienti.Show vbModal
        Case Mask.LIBRI
            Load MascheraLibri
            MascheraLibri.Show vbModal
    End Select
    Set objMaskLoc = Nothing
    cnMiaConnessione.Close
    Set cnMiaConnessione= Nothing
End Sub
'Questa routine pubblica viene chiamata dalle mie form per generare
l'evento.
'lngID è una variabile public dichiarata in un modulo bas.
'Gestisce l'ID del record, sia che sia un libro, un cliente, ecc...
Public Sub sRaiseEvent(Azione As String)
    RaiseEvent eRefresh(lngID, Azione)
End Sub
*****************************************
Questo è parte del codice della form MascheraLibri
*****************************************
Private Sub sModificaLibro()
Dim rcAppo As ADODB.Recordset
Dim strSql As String
    If fVerificaDati Then
        'Qui c'è il codice che modifica il mio libro
        .....
        .....
        'Ora genero l'evento...
        objMaskLoc.sRaiseEvent ("Modifica")
    End If
End Sub
Spero che sia chiaro il meccanismo. So che può sembrare strano il modo in
cui agisco,
cioè passare come parametro al mio oggetto, se stesso. E poi istanziare
all'interno della mia dll
un oggetto uguale a se stesso... non so come spiegarmi :)
Però così funziona... se eseguo a runtime... se compilo invece non funzia.
Anche se non è del tutto vero. Ad essere precisi, se nel programma, nei
riferimenti, uso un riferimento al vbp della dll,
tutto funziona perfettamente. Ma se compilo la dll, e uso un riferimento
alla .dll e non al vbp della dll,
non funzia più, nemmeno a runtime.
Non so come fare... come si fa a far notificare gli eventi allora??? Mi
sembra che il problema che ho incontrato è generarli
da una form aperta (adesso non so se la modalità vbmodal influisca o no).
Se dovessi generare un evento dalla modulo di classe stesso, tutto ok. Ma da
una form non va.
Spero di essere stato chiaro, per questo mi sono dilungato.
Grazie a tutti. Ciao :)

da una form aperta (adesso non so se la modalità vbmodal influisca o no).
in _teoria_ dovrebbe funzionare, ma effettivamente mi e' capitato che alcuni
eventi si perdessero per strada, magari solo su alcuni pc.
Un workaround che avevo adottato e' stato il ricorso a callback. In pratica,
scrivevo una classe con solo metodi e proprieta', ma senza codice dentro
(praticamente definivo un' interfaccia).
Tale interfaccia veniva implementata dal chiamante che passava se stesso
(tramite l' interfaccia implementata) all' oggetto chiamato.
Al momento del RaiseEvent, la dll chiamata il metodo opportuno dell' interfaccia
ricevuta dal/dai client.
Il vantaggio di questa tecnica e' che funziona sempre e si ha il controllo della
sequenza degli eventi se i client sono piu' di uno.
Lo svantaggio e' che e' un po' piu' laboriosa (ma non tanto) del ricorso agli eventi
e bisogna che il server dll azzeri i riferimenti alle interfacce prima che venga 
impostato a nothing perche' vb potrebbe non riuscire a scaricarlo.
(Con quella variabile oggetto nel .bas mi sa che imballi vb e succeda qualcosa del
genere.)
ciao, hal

 ciao, hal
Ciao e grazie tante.
Un'ultima richiesta, non è che potresti mandarmi qualche riga di codice in
cui mi fai vedere come implementare
questa interfaccia?
Magari un form che chiama una dll; in questa dll apro un'altra form. In
quest'ultima c'è un pulsante che se lo clicco
mi notifica un evento che scrive qualcosa sulla form chiamante.
Sempre se puoi :)
Intanto mi rileggo qualcosa riguardo a callback... e che Dio me la mandi
buona.

 Eheheh, non si finisce mai di imparare, soprattutto l'italiano :)
gia', specie quando ormai e' normale la forma
    achille piè veloce
dal che si deduce...
hal, consolati: anche a me "pò" fa aggricciare :)
ciao, a.