Intercettare eventi subform dentro una classe

di il
10 risposte

Intercettare eventi subform dentro una classe

Sto cercando di intercettare gli eventi scatenati in un subform per gestirli all'interno di una classe.
Attualmente ho un form che contiene 1 subform. Nel form ho dichiarato ed instanziato una classe che ha tra gli altri compiti, quello di ricevere gli eventi provenienti dai controlli (label, text,button, etc) presenti nel form e nel subform e gli eventi provenienti dal form e dai subform (afterupdate, dirty, etc). Riesco a intercettare gli eventi che mi interessano tranne gli eventi dei subform (i.e. dirty).

Ecco un poco di codice ...

ANCF_REPL (Form Principale) :

Public WithEvents mFMR         As clsFormRepl          ' Classe principale (DEVE ESSERE PUBLIC)

Private Sub Form_Load()
  
    Set mFMR = New clsFormRepl
    ' routine che carica i controlli per i quali voglio gestire gli eventi
    Dummy = mFMR.FormREPL_Load(Me)
    ....
End Sub
clsFormRepl (Classe) :
Nota : questa classe memorizza in una collection i controlli per i quali voglio gestire gli eventi. Per questo scopo viene utilizzata la classe cls_EVListener_REPL (mostrata successivamente).

Private WithEvents mFCaller As Access.Form      ' Form Chiamante
Private mColControls            As Collection          ' Collection di controlli del form chiamante

Private Sub Class_Initialize()
    Set mFCaller = Application.CodeContextObject
    Set mColControls = New Collection
    ...
End Sub

Public Function FormREPL_Load(accFR As Access.Form) As Boolean
    ' Carica collection di Controlli
    mDummy = REPL_LoadControls(accFR)
    ...
End Sub

Private Function REPL_LoadControls(ReplForm As Access.Form) As Boolean
Dim ctItem      As control
Dim sKey        As String
Dim iFind       As Integer

    '
    ' Funzione ricorsiva : passo il riferimento del form chiamante (non uso MFCaller)
    '
    For Each ctItem In ReplForm.Controls
        If ctItem.ControlType = acSubform Then
            sKey = "C" & Format(Me.CountControl + 1, "0000")
            AddControl ctItem, sKey
            '
            mDummy = REPL_LoadControls(ctItem.Form)
        Else
            '
            ' Memorizzo i Controlli per i quali voglio, eventualmente,
            '   gestirne gli eventi in Cls_EvListener_REPL
            '
            Select Case ctItem.ControlType
            Case Is = acCommandButton
                '
             Case Is = acLabel
               If ctItem.Parent.Name = ReplForm.Name Then
                      If InStr(1, UCase(ctItem.Name), "TITLE") > 0 Then
                        sKey = "C" & Format(Me.CountControl + 1, "0000")
                        AddControl ctItem, sKey
                    End If
                End If
            End Select
        
        End If
        DoEvents
    Next ctItem
    Set ctItem = Nothing
    REPL_LoadControls = True
End Function

Private Function AddControl(obj As control, sKey As String) As Boolean
Dim curClass As cls_EvListener_REPL

    If Not ExistsControl(sKey) Then
        Set curClass = New cls_EvListener_REPL
        curClass.SetObjectControl obj, Me
        curClass.Key = sKey
	' memorizzo in una collection i controlli
        mColControls.Add curClass, sKey
    Else
        Set curClass = mColControls(obj.Name)
    End If

    Set curClass = Nothing
    AddControl = True
End Function

Private Sub mFCaller_Dirty(cancel As Integer)
    
    'Evento Dirty (del FORM principale) nella classe : regolarmente intercettato
End Sub 
cls_EvListener_REPL (Classe che intercetta gli eventi dei controlli)

Private mParent             As clsFormRepl      ' Classe Chiamante
Private mPassedCtrl         As control

Private WithEvents Lbl      As Access.Label
Private WithEvents SFm      As Access.SubForm
....

Public Property Set control(ByRef PassedControl As control)
    Set mPassedCtrl = PassedControl
    '
    ' Aggiungere gli eventi da gestire per ogni controllo
    '
    Select Case TypeName(mPassedCtrl)
    Case "Label"
        ' Gli eventi sulla label sono disponibili SOLO se la label è detached ...
        mPassedCtrl.OnClick = "[Event Procedure]"
        Set Lbl = mPassedCtrl
    Case "SubForm"
        mPassedCtrl.Form.OnDirty = "[Event Procedure]"   -> FORSE Sbaglio la sintassi per intercettare l'evento
        Set SFm = mPassedCtrl
    ....
    End Select

    '
    ' Nota : occorre creare le sub degli eventi da gestire per i vari tipi di controllo
    ' i.e. : evento Click su CommandButton -> Public Sub Btn_Click()
    '
End Property

Public Sub SetObjectControl(ctl As control, ParentClass As clsFormRepl)
    Set Me.Parent = ParentClass
    Set Me.control = ctl
End Sub

Public Sub SFm_Dirty(cancel As Integer)

    ' Evento Dirty Subform nella Classe -> questo evento NON riesco ad intercettarlo

End Sub

Public Sub Lbl_Click()

    ' Evento Click su label in SubFrom nella Classe  -> questo evento riesco ad intercettarlo

End Sub
Credo di aver inserito le parti salienti di codice.
Di fatto riesco ad intercettare gli eventi provenienti dai controlli presenti nel subform ma non riesco ad intercettare gli eventi del subform stesso.

Credo che la parte incriminata sia in questa parte di codice :

    Case "SubForm"
        mPassedCtrl.Form.OnDirty = "[Event Procedure]"   -> FORSE Sbaglio la sintassi per intercettare l'evento
        Set SFm = mPassedCtrl
Se scrivo mPassedCtrl.OnDirty ottengo errore runtime 438 (proprietà o metodo non supportati dall'oggetto).

Sono conscio che si tratta di un utilizzo non proprio basico di Access ma spero che qualcuno intraveda quello che a me sfugge.

10 Risposte

  • Re: Intercettare eventi subform dentro una classe

    Il controllo SubForm nella collection è il container... tu devi puntare all'oggetto form del container.

    Prova a modificarlo cosi:
    
    AddControl ctItem.Form, sKey
    
    Stessa cosa nell'altra classe...
    Avevo fatto parecchi esempi sul Multicasting... nelle classi
  • Re: Intercettare eventi subform dentro una classe

    Grazie Alex,
    c'ero arrivato vicino ma mi mancava qualcosa ... ecco la soluzione:
    
    Private WithEvents SForm    As Access.Form          ' Form
    ....
        Case "SubForm"
            mPassedCtrl.Form.OnDirty = "[Event Procedure]"
             Set SForm = mPassedCtrl.Form        'Controllo SubForm.Form -> diventa Form
    
    In pratica usavo il subform come controllo invece di usarlo come oggetto form ...
  • Re: Intercettare eventi subform dentro una classe

    @Alex ha scritto:


    Avevo fatto parecchi esempi sul Multicasting... nelle classi
    Da dove credi che arrivi la 'mia' tecnica di intercettare gli eventi ?
  • Re: Intercettare eventi subform dentro una classe

    max.riservo ha scritto:


    ....
    Da dove credi che arrivi la 'mia' tecnica di intercettare gli eventi ?
    Allora è OTTIMA
  • Re: Intercettare eventi subform dentro una classe

    Io però preferisco usare la proprietà ControlType per il casting... oppure il [TypeOf Obj Is NomeClasseOggetto]
    
    Select Case ctl.ControlType
            Case Is = acTextBox
            Case Is = acLabel    
            Case Is = acComboBox
            Case Is = acListBox
            Case Is = acCheckBox
            ' ecc...
    End Select
    
    Select Case True
            Case TypeOf ctl Is TextBox
            Case TypeOf ctl Is Label    
            Case TypeOf ctl Is ComboBox
            Case TypeOf ctl Is ListBox
            Case TypeOf ctl Is CheckBox
            Case TypeOf ctl Is NomeTuaCustomClass 
            ' ecc...
    End Select
    La seconda ha il vantaggio che riesci a discriminare anche gli Oggetti NON NATIVI che non hanno un valore nella Enum [Access.AcControlType] leggibile dalla Proprietà ControlType, ma anche le Classi Custom che ti puoi creare.
  • Re: Intercettare eventi subform dentro una classe

    @Alex ha scritto:


    Io però preferisco usare la proprietà ControlType per il casting... oppure il [TypeOf Obj Is NomeClasseOggetto]
    ...
    La seconda ha il vantaggio che riesci a discriminare anche gli Oggetti NON NATIVI che non hanno un valore nella Enum [Access.AcControlType] leggibile dalla Proprietà ControlType, ma anche le Classi Custom che ti puoi creare.
    Buono a sapersi ...

    Ho notato che gli eventi generati dal form/subform vengono intercettati SOLO se è presente l'event handler nel form/subform (con un commento al suo interno) :
    
    Private Sub Form_Delete(cancel As Integer)
        ' TASSATIVO : lasciare dichiarato l'event handler per poter ricevere l'evento nella classe !!!
    End Sub
    
    Per quanto riguarda gli eventi generati dai controlli questa accortezza non è necessaria.

    Sei a conoscenza se sia possibile evitare anche questo piccolo 'fastidio'?
  • Re: Intercettare eventi subform dentro una classe

    No non mi risulta ma serve che la Form/SubForm abbia il modulo VBA GENERATO.
    Come sai una form nuova non ha la proprietà HasModule=True, e diventa true solo se attivi codice nella stessa.
    Se non generi il Modulo ovviamente gli eventi non vengono generati nemmeno nella classe.
    Magari verifica se sto dicendo una cavolata ma a memoria era così...
    Tuttavia in VB6 si faceva così con gli OCX e le Classi... quindi potrebbe essere anche corretto, solo che non lo ricordo così rigido.
  • Re: Intercettare eventi subform dentro una classe

    Ho letto anche io che è necessario che la proprietà HasModule deve essere a True, in nel form/subform codice ne ho ( e HasModule è = True), quindi penso che non ci sia alcun'altra possibilità che inserire un commento nell'event handler.
    Provo ad indagare ulteriormente, magari trovo qualcosa ...
  • Re: Intercettare eventi subform dentro una classe

    In ogni caso ho guardato un mio demo ed in effetti ho dovuto implementare l'eventhandler nella form per farlo vedere nella classe, e confermo che per i controlli non accade.

    Ora sinceramente non ricordo la Genesi del problema ma la soluzione è quella.
  • Re: Intercettare eventi subform dentro una classe

    Diciamo che è un male secondario ... me ne farò una ragione
Devi accedere o registrarti per scrivere nel forum
10 risposte