Rimozione sottoscrizione evento

di il
5 risposte

Rimozione sottoscrizione evento

Salve a tutti,
mi trovo con con un problema di mancanza di "distruzione" della catena di eventi...
poniamo il semplicissimo caso di un windows form che puo' gestire l'oggetto X... l'oggetto X e' un'implementazione di un'interfaccia...
la form ha una textbox, una combobox, un button, e una listbox
la combo indica le tipologie di "oggetto X" (oggetto che implementa una interfaccia X) e che e sara' caricato via reflection di tutte queste implementazioni poi riscontratate... in queso mini scenario preparatato cio' non avviene e il combo carica "2 nomi" di "oggetto X" per poter selezionarne la tipologia (che qui e' comunque unica)
il fine ultimo, qui, e' caricare la listbox in caso di evento text_change, evento che correttamente avviene nel form e quindi viene passato alla classe...
MA... man mano che le istanze della classe vengono distrutte, non si sganciano le sottoscrizione all'evento, che viene sollevato N volte per quante volte la classe e' stata "rigenerata"...

la distruzione dell'oggetto c'e', e non capisco cosa manchi...
Friend Class Form1

    Friend TextBox1 As TextBox = Nothing
    Friend ComboBox1 As ComboBox = Nothing
    Friend Button1 As Button = Nothing
    Friend ListBox1 As ListBox = Nothing

    Private m_objectReference As amTest = Nothing

    Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs)

        Me.ListBox1.Items.Add("-> dal form")

    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Init_Component()

        Me.ComboBox1.Items.Add("test1")
        Me.ComboBox1.Items.Add("test2")
        Me.ComboBox1.SelectedIndex = 0

        AddHandler TextBox1.TextChanged, AddressOf TextBox1_TextChanged
        AddHandler Button1.Click, AddressOf Button_Click

    End Sub

    Private Sub Init_Component()

        Me.TextBox1 = New System.Windows.Forms.TextBox()
        Me.ComboBox1 = New System.Windows.Forms.ComboBox()
        Me.Button1 = New System.Windows.Forms.Button()
        Me.ListBox1 = New System.Windows.Forms.ListBox()
        Me.SuspendLayout()
        '
        'TextBox1
        '
        Me.TextBox1.Location = New System.Drawing.Point(12, 35)
        Me.TextBox1.Name = "TextBox1"
        Me.TextBox1.Size = New System.Drawing.Size(100, 20)
        Me.TextBox1.TabIndex = 0
        '
        'ComboBox1
        '
        Me.ComboBox1.FormattingEnabled = True
        Me.ComboBox1.Location = New System.Drawing.Point(139, 35)
        Me.ComboBox1.Name = "ComboBox1"
        Me.ComboBox1.Size = New System.Drawing.Size(60, 21)
        Me.ComboBox1.TabIndex = 1
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(210, 33)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(150, 23)
        Me.Button1.TabIndex = 2
        Me.Button1.Text = "<- : nuova istanza"
        Me.Button1.UseVisualStyleBackColor = True
        '
        'ListBox1
        '
        Me.ListBox1.FormattingEnabled = True
        Me.ListBox1.Location = New System.Drawing.Point(12, 79)
        Me.ListBox1.Name = "ListBox1"
        Me.ListBox1.Size = New System.Drawing.Size(366, 160)
        Me.ListBox1.TabIndex = 3
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(388, 250)
        Me.Controls.Add(Me.ListBox1)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.ComboBox1)
        Me.Controls.Add(Me.TextBox1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub

    Private Sub Button_Click(sender As Object, e As EventArgs)

        Me.m_objectReference = Nothing   ' <- distruzione riferimento
        Me.ListBox1.Items.Clear()

        Dim param As New amConnector With {.TextValue = Me.ComboBox1.SelectedItem}
        param.ManagedControls.Add(Me.TextBox1)
        param.ManagedControls.Add(Me.ListBox1)
        param.typeValue = Me.ComboBox1.SelectedItem

        Me.m_objectReference = New amTest
        Me.m_objectReference.InitData(param)

    End Sub

End Class


Public Interface amObject

    Sub InitData(ByRef e As amConnector)

End Interface


Public Class amConnector

    Public Property typeValue As String = ""
    Public Property TextValue As String = ""
    Public Property ManagedControls As New List(Of Windows.Forms.Control)

End Class


Public Class amTest
    Implements amObject

    Private m_txt As System.Windows.Forms.TextBox = Nothing
    Private m_list As System.Windows.Forms.ListBox = Nothing

    Public Sub InitData(ByRef e As amConnector) Implements amObject.InitData

        For Each ctl As System.Windows.Forms.Control In e.ManagedControls
            Select Case True
                Case TypeOf ctl Is TextBox
                    m_txt = CType(ctl, System.Windows.Forms.TextBox)
                Case TypeOf ctl Is ListBox
                    m_list = CType(ctl, System.Windows.Forms.ListBox)
            End Select
        Next
        m_list.Items.Clear()
        m_txt.Text = e.TextValue
        m_txt.Tag = e.typeValue

        AddHandler Me.m_txt.TextChanged, AddressOf TextBox1_TextChanged

    End Sub

    Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs)
        If Not Me.m_list Is Nothing Then
            Me.m_list.Items.Add(String.Format("-> dalla classe [{0}]", Me.m_txt.Tag))
        End If
    End Sub

End Class
[edit]
ok, dopo crisi ipogligemica mi sono riletto e forse non e' molto chiaro, comunque, ad ogni pressione del "button", dopo la distruzione del riferimento alla classe, si istanzia un nuovo riferimento alla classe che implementa l'interfaccia, ma agli eventi nella classe NON vengono rimosse le "vecchie sottoscrizioni all'evento"... che quindi "si sommano"
[/edit]
salutoni romagnoli e grazie per eventuali suggerimenti
--
Andrea

5 Risposte

  • Re: Rimozione sottoscrizione evento

    Forse, anzi probabilmente, non ho capito nulla del problema, ma non basta richiamare RemoveHandler quando l'oggetto che si è iscritto alla gestione dell'evento viene distrutto?

    In questo modo, il gestore (ossia il metodo che viene invocato quando si scatena l'evento) viene rimosso dalla lista interna delle sottoscrizioni all'evento stesso.

    Ciao!
  • Re: Rimozione sottoscrizione evento

    Ciao Marco,
    grazie per il feedback...
    lo so, ero in ipoglicemia e non sono stato molto chiaro... ora mi son bevuto 15 gr di destrosio
    allora... il form di esempio dovrebbe utilizzare un oggetto_classe che implementa un'interfaccia... in base alla scelta della combo, si istanzia un'oggetto diverso (in questo esempio e' unico e sempre lui)... a questo oggetto vengono passati tra i parametri dei controlli winform... al momento dell'inizializzazione e passaggio dei parametri, la classe istanzia i controlli prendendoli dai parametri e farebbe gli addhandler...
    la classe non ha un distruttore, quindi niente removehandlers, e non mi viene in mente niente di intelligente se non aggiungere all'oggetto anche l'interfaccia disposable, che andrebbe pero' manualmente richiamata prima di distruggere l'oggetto nel winform, e nel dispose fare i removehandlers... e vedere se funziona
    no ho provato ad aggiungere un Protected Overrides Sub Finalize() e metterli li' dentro, ma ho idea che non vengano chiamati dal garbage collector a meno di non forzarne il Collect...

    se avesse senso implementare anche idisposable, devo pero' vedere pero' "come" passare da
    Private m_objectReference As amTest ' <- che e' un'altra interfaccia
    all'utilizzo di dispose, visto che non si possono mettere riferimenti da altre interfaces nella dichiarazione di un'interface...

    non so se sono stato piu' chiaro, oggi non sono in forma
    comunque grazie per eventuali feedback...
    salutoni romagnoli
    --
    Andrea
  • Re: Rimozione sottoscrizione evento

    asql ha scritto:


    la classe non ha un distruttore, quindi niente removehandlers, e non mi viene in mente niente di intelligente se non aggiungere all'oggetto anche l'interfaccia disposable, che andrebbe pero' manualmente richiamata prima di distruggere l'oggetto nel winform, e nel dispose fare i removehandlers... e vedere se funziona
    Per me, è indispensabile procedere in questo modo.

    asql ha scritto:


    se avesse senso implementare anche idisposable, devo pero' vedere pero' "come" passare da
    Private m_objectReference As amTest ' <- che e' un'altra interfaccia
    all'utilizzo di dispose, visto che non si possono mettere riferimenti da altre interfaces nella dichiarazione di un'interface...
    La tua interfaccia può dichiarare di "derivare", o meglio "estendere" IDisposable.
    
    interface IMyIntf : IDisposable
    {
    }
    

    asql ha scritto:


    salutoni romagnoli
    Saluti emiliani!
  • Re: Rimozione sottoscrizione evento

    Salve Marco,
    grazie, non avevo pensato a ereditare da Idisposable, ma solo ad aggiungere alla mia interface un'altra interface o implementare al suo interno un'altra, cosa che ovviamente non si puo' fare...

    salutoni romagnoli
    --
    Andrea
  • Re: Rimozione sottoscrizione evento

    Grazie Marco,
    ereditando da IDispose, mettendo tutti i cleanup di removehandler necessari, ed ovviamente richiamando .Dispose, ho risolto il problema
    grazie
    salutoni romagnoli
    --
    Andrea
Devi accedere o registrarti per scrivere nel forum
5 risposte