Modelli WeakEvent
Aggiornamento: novembre 2007
Nelle applicazioni comuni, è possibile che gestori associati a origini evento non saranno 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 particolare che può essere utilizzato per risolvere questo problema, fornendo una classe di gestione dedicata per eventi particolari e implementando un'interfaccia sui listener relativi a quell'evento. Questo modello di progettazione è noto come modello WeakEvent.
Vantaggi offerti dall'implementazione del modello WeakEvent
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. Ad esempio, in C# tale sintassi è la seguente: source.SomeEvent += new SomeEventHandler(MyEventHandler).
Questa tecnica crea un riferimento forte dall'origine evento al listener di eventi. Di norma, se si associa un gestore eventi per un listener la durata del listener è influenzata dalla durata dell'origine (a meno che il gestore eventi non venga rimosso in modo esplicito). Tuttavia, in determinate circostanze è possibile che si decida che la durata del listener sia controllata unicamente 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 WeakEvent è progettato per risolvere questo problema di perdita di memoria e può essere utilizzato in tutti i casi in cui è necessario che un listener si registri per un evento ma non è in grado di conoscere in modo esplicito il momento in cui annullare la registrazione e tutti i casi in cui la durata dell'origine supera la durata "utile" del listener. La definizione del concetto di "utile" spetta all'utente. Il modello WeakEvent consente al listener di registrarsi per l'evento e riceverlo senza influire in alcun modo sulle caratteristiche di durata del listener. In effetti, il riferimento implicito dall'origine non conta quando si decide se il listener è idoneo per il Garbage Collection. Si tratta di un riferimento debole, da cui la denominazione del modello WeakEvent e delle API 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 WeakEvent
L'implementazione del modello WeakEvent 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. Tale responsabilità include il comportamento relativo alla durata del controllo, in particolare la gestione del problema della perdita di memoria descritto.
Determinati scenari si prestano implicitamente all'applicazione del modello WeakEvent. Uno di questi scenari è l'associazione dati, in cui spesso è necessario che un oggetto origine, vale a dire un'origine dati sia completamente indipendente da un oggetto listener, ovvero una destinazione di un'associazione. Il modello WeakEvent viene già applicato a molti aspetti dell'associazione dati di WPF rispetto al modo in cui vengono implementati gli eventi.
Modalità di implementazione del modello WeakEvent
L'implementazione del modello WeakEvent è costituita da tre aspetti:
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. Utilizzare, invece, le implementazioni di "AddListener" e "RemoveListener" nell'oggetto WeakEventManager relativo a quell'evento.
WeakEventManager
In genere, verranno create classi di gestione con un rapporto 1:1 per gli eventi che implementano il modello. Se, ad esempio, si dispone di un evento Spin, verrà derivata una classe SpinEventManager come gestore degli eventi deboli dedicato per l'evento. Se l'evento è presente in più classi di origine e in genere si comporta in modo identico in ogni classe, condividendo lo stesso tipo di dati evento è possibile utilizzare lo stesso gestore per ogni classe.
L'elenco di controllo delle implementazioni per derivare dalla classe WeakEventManager è costituito dall'esecuzione dell'override di due metodi virtuali e dall'esposizione di molti 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 sono necessari per fornire la funzionalità che consente alle implementazioni di IWeakEventListener di utilizzare WeakEventManager per associare dei listener all'evento.
Per le note di implementazione dettagliate per derivare da WeakEventManager, vedere le note per gli eredi nell'argomento di riferimento relativo a WeakEventManager.
IWeakEventListener
L'unica responsabilità di una classe di implementazione IWeakEventListener consiste nell'implementare il metodo di interfaccia 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 le note di implementazione dettagliate per implementare l'interfaccia IWeakEventListener, vedere le note per gli implementatori nell'argomento di riferimento del metodo ReceiveWeakEvent.
Associazione di listener
Si supponga di disporre di un evento ClockwiseSpin (definito da Spinner) che è un evento convenzionale. Per utilizzare il modello per questo evento è possibile utilizzare una classe ClockwiseSpinEventManager esistente derivata da WeakEventManager oppure implementarne una creata appositamente. Se si dispone di una classe listener SpinListener da utilizzare come listener, la tecnica convenzionale (senza utilizzare il modello) per associare il gestore consiste nell'utilizzare la sintassi + =:
spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);
Se tuttavia si dispone di una classe che implementa IWeakEventListener e tiene conto dell'evento ClockwiseSpin e del relativo gestore nell'implementazione, la sintassi da utilizzare per il modello WeakEvent è invece la seguente:
ClockwiseSpinEventManager.AddListener(spinnerInstance, this);
Pertanto, 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 WeakEvent consiste nella possibilità di implementare il modello per un evento che non è parte del codebase utilizzato. Dalla prospettiva dell'origine, il modo in cui i gestori vengono associati ai relativi eventi non differisce ed è controllato da WeakEventManager. È sufficiente definire un WeakEventManager per quell'evento e quindi tenere conto di quell'evento all'interno della logica ReceiveWeakEvent per tutti i potenziali listener desiderano utilizzare il modello per ascoltare quell'evento.
Vedere anche
Concetti
Cenni preliminari sugli eventi indirizzati
Cenni preliminari sull'associazione dati