Modelli di eventi deboli

Nelle applicazioni, è possibile che i gestori associati a origini evento non vengano eliminati insieme all'oggetto listener che ha associato il gestore all'origine. Tale situazione può causare perdite di memoria. Windows Presentation Foundation (WPF) introduce un modello di progettazione che può essere utilizzato per risolvere questo problema, fornendo una classe di gestione dedicata per eventi particolari e implementando un'interfaccia nei listener relativi all'evento in questione. Questo modello di progettazione è noto come modello di evento debole.

Vantaggi offerti dall'implementazione del modello di evento debole

L'utilizzo di listener di eventi può causare perdite di memoria. La tecnica standard di ascolto di un evento consiste nell'utilizzare la sintassi specifica del linguaggio che associa un gestore a un evento in un'origine. In C#, ad esempio, la sintassi è la seguente: source.SomeEvent += new SomeEventHandler(MyEventHandler).

Questa tecnica crea un riferimento forte dall'origine evento al listener di eventi. Di norma, l'associazione di un gestore eventi per un listener fa sì che la durata dell'oggetto del listener sia influenzata dalla durata dell'oggetto dell'origine, a meno che il gestore eventi non venga rimosso in modo esplicito. In determinate circostanze, tuttavia, è possibile che la durata dell'oggetto del listener sia controllata da altri fattori, ad esempio l'eventuale appartenenza del listener alla struttura ad albero visuale dell'applicazione, non dalla durata dell'origine. Se la durata dell'origine va oltre la durata del listener, il modello di eventi standard causa una perdita di memoria: il listener viene tenuto vivo più a lungo di quanto previsto.

Il modello di evento debole è progettato per risolvere questo problema di perdita di memoria e può essere utilizzato ogni qualvolta un listener deve effettuare la registrazione per un evento ma non conosce in modo esplicito il momento in cui annullare la registrazione. Il modello di evento debole può inoltre essere utilizzato ogni qualvolta la durata dell'oggetto dell'origine supera la durata dell'oggetto utile del listener. In questo caso, utile è determinato dall'utente. Il modello di evento debole consente al listener di registrarsi per l'evento e riceverlo senza influire in alcun modo sulle caratteristiche di durata dell'oggetto del listener. Di fatto, il riferimento implicito dall'origine non determina l'eventuale idoneità del listener per Garbage Collection. Si tratta di un riferimento debole, da cui la denominazione del modello di evento debole e delle APIs correlate. Il listener può essere sottoposto a Garbage Collection o altrimenti eliminato e l'origine può continuare senza mantenere riferimenti del gestore non sottoponibili a Garbage Collection relativi a un oggetto ora eliminato.

Identificazione dei soggetti più indicati per l'implementazione del modello di evento debole

L'implementazione del modello di evento debole sarà interessante soprattutto per gli autori dei controlli, responsabili in larga parte del comportamento e del contenimento del controllo oltre che dell'impatto che questo ha sulle applicazioni nelle quali viene inserito. Ciò include il comportamento relativo alla durata dell'oggetto del controllo, in particolare la gestione del problema di perdita di memoria descritto.

Determinati scenari si prestano implicitamente all'applicazione del modello di evento debole. Uno di questi è l'associazione dati. Nell'associazione dati accade comunemente che l'oggetto di origine sia completamente indipendente dall'oggetto listener, che è una destinazione di un'associazione. Il modello di evento debole viene già applicato a molti aspetti dell'associazione dati WPF rispetto al modo in cui vengono implementati gli eventi.

Modalità di implementazione del modello di evento debole

L'implementazione del modello di evento debole è costituita dai tre aspetti seguenti:

  • Derivazione di un gestore dalla classe WeakEventManager.

  • Implementazione dell'interfaccia IWeakEventListener su qualsiasi classe desideri registrare listener per l'evento debole senza generare un riferimento forte all'origine.

  • Quando si registrano dei listener, non utilizzare le funzioni di accesso add e remove dell'evento nel quale si desidera che il listener utilizzi il modello. Al contrario, utilizzare le implementazioni AddListener e RemoveListener nell'oggetto WeakEventManager dedicato per tale evento.

WeakEventManager

Per implementare il modello di evento debole, in genere si crea una classe di gestione in relazione 1:1 con l'evento. Se, ad esempio, si dispone di un evento denominato Spin, si creerà una classe SpinEventManager che rappresenta il gestore di evento debole dedicato per l'evento. Se l'evento è presente in più classi, si comporta in genere in modo identico in ogni classe e condivide lo stesso tipo di dati evento, è possibile utilizzare lo stesso gestore per ogni evento.

Quando si esegue una derivazione dalla classe WeakEventManager, si esegue l'override di due metodi virtuali e si espongono diversi altri membri i cui nomi non sono determinati in modo specifico da un modello virtuale, ma che tuttavia devono esistere. Gli override sono utilizzati per iniziare o terminare la modalità di recapito eventi da parte dell'infrastruttura WPF. Gli altri membri forniscono la funzionalità che consente alle implementazioni di IWeakEventListener di utilizzare WeakEventManager per associare i listener all'evento.

Per ulteriori informazioni sulla derivazione da WeakEventManager, vedere la sezione "Note per gli eredi" nell'argomento di riferimento relativo a WeakEventManager.

IWeakEventListener

L'interfaccia di IWeakEventListener presenta un unico metodo denominato ReceiveWeakEvent. L'implementazione di ReceiveWeakEvent deve essere un'implementazione centralizzata che indirizza qualsiasi riferimento a un evento presente in quella classe all'oggetto WeakEventManager appropriato.

Per ulteriori informazioni sull'implementazione dell'interfaccia di IWeakEventListener, vedere la sezione "Note per gli implementatori" nell'argomento di riferimento del metodo ReceiveWeakEvent.

Associazione di listener

Si supponga di disporre di un evento ClockwiseSpin, definito da un tipo Spinner, che rappresenta un evento convenzionale. Se si dispone di una classe listener SpinListener da utilizzare come listener, la tecnica convenzionale per associare il gestore senza utilizzare il modello di evento debole consiste nell'utilizzare l'operatore "+=":

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

Se si dispone di una classe che implementa IWeakEventListener e tiene conto dell'evento ClockwiseSpin e del relativo gestore nell'implementazione, la sintassi per utilizzare il modello di evento debole è la seguente:

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

La logica di gestione per quell'evento viene specificata all'interno di uno dei casi dell'implementazione di ReceiveWeakEvent nella classe, non come gestore convenzionale basato sul delegato.

Implementazione del modello per gli eventi esterni

Un aspetto interessante del modello di evento debole consiste nella possibilità di implementare il modello per un evento che non fa parte della codebase utilizzata. Dalla prospettiva dell'origine, il modo in cui i gestori vengono associati ai relativi eventi non differisce ed è controllato da WeakEventManager. È sufficiente definire un oggetto WeakEventManager per l'evento e quindi tenere conto dell'evento come parte della logica di ReceiveWeakEvent per tutti i potenziali listener che desiderano utilizzare il modello di evento debole per ascoltare l'evento.

Vedere anche

Riferimenti

WeakEventManager

IWeakEventListener

Concetti

Cenni preliminari sugli eventi indirizzati

Cenni preliminari sull'associazione dati