Modelos WeakEvent

Actualización: noviembre 2007

En las aplicaciones típicas, es posible que los controladores que se asocian a los orígenes de eventos no se destruirán en coordinación con el objeto de agente de escucha que asoció el controlador al origen. Esta situación puede provocar pérdidas de memoria. Windows Presentation Foundation (WPF) introduce un modelo de diseño concreto que se puede utilizar para resolver este problema; para ello, proporciona una clase de administrador dedicada para eventos concretos e implementa una interfaz para los agentes de escucha de ese evento. Este modelo de diseño se denomina modelo WeakEvent.

¿Por qué implementar el modelo WeakEvent?

Realizar escuchas de eventos puede provocar pérdidas de memoria. La técnica típica para realizar escuchas de eventos consiste en utilizar la sintaxis específica del lenguaje que asocia un controlador a un evento en un origen. Por ejemplo, en C#, esa sintaxis es: source.SomeEvent += new SomeEventHandler(MyEventHandler).

Esta técnica crea una referencia segura desde el origen de evento al agente de escucha de evento. En general, al asociar un controlador de eventos para un agente de escucha, la duración de objeto del origen influye en la duración de objeto del agente (a menos que el controlador de eventos se quite explícitamente). Sin embargo, en determinadas circunstancias puede ser conveniente controlar la duración de objeto del agente de escucha tan sólo mediante otros factores, tales como si pertenece actualmente al árbol visual de la aplicación, y no mediante la duración del origen. Cada vez que la duración de objeto del origen es superior a la del agente de escucha, el modelo de eventos normal provoca una pérdida de memoria: el agente de escucha se mantiene activo más tiempo del previsto.

El modelo WeakEvent está diseñado para resolver este problema de pérdida de memoria. El modelo WeakEvent se puede usar siempre que un agente de escucha necesite registrarse para un evento pero no conozca explícitamente cuándo debe cancelar ese registro, y siempre que la duración de objeto del origen supere la del objeto "útil" del agente de escucha. (Corresponde al programador definir el concepto de "útil".) El modelo WeakEvent permite al agente de escucha registrarse para el evento y recibirlo sin que ello afecte en modo alguno a sus características de duración de objeto. En efecto, la referencia implícita del origen no se tiene en cuenta al decidir si el agente de escucha es apto para la recolección de elementos no utilizados. Se trata de una referencia débil ("weak", en inglés), concepto del que toman su nombre el modelo WeakEvent y las API relacionadas. El agente de escucha puede someterse a la recopilación de elementos no utilizados o destruirse de alguna otra forma, y el origen puede continuar sin conservar las referencias al objeto que se ha destruido no recopilables en el controlador.

¿Quién debe implementar el modelo WeakEvent?

Implementar el modelo WeakEvent resulta interesante principalmente para los autores de controles. Esto se debe a que el autor de un control es responsable en gran medida del comportamiento y la contención del control y del efecto que ejerce en las aplicaciones en las que se inserta. Esto incluye el comportamiento de la duración de objeto del control, y en particular la administración del problema de pérdida de memoria descrito.

Algunos escenarios se prestan de forma inherente a la aplicación del modelo WeakEvent. Uno de ellos es el enlace de datos, donde suele suceder que un objeto de origen, que es un origen de datos, sea completamente independiente de un objeto de agente de escucha, que es un destino de enlace. El modelo WeakEvent ya se aplica a muchos aspectos del enlace de datos de WPF en lo relativo a cómo se implementan los eventos.

Cómo implementar el modelo WeakEvent

La implementación del modelo WeakEvent se divide en tres aspectos:

  • Derivar un administrador de la clase WeakEventManager.

  • Implementar la interfaz IWeakEventListener en cualquier clase que desee registrar agentes de escucha para el evento débil sin generar una referencia segura al origen.

  • Al registrar los agentes de escucha, no utilice los descriptores de acceso convencionales de agregar y quitar del evento donde desea que el agente de escucha utilice el modelo. En su lugar, utilice las implementaciones de "RemoveListener" y "AddListener" del objeto WeakEventManager dedicado para ese evento.

WeakEventManager

Normalmente, se crean las clases de administrador en relación 1:1 a los eventos que implementan el modelo. Por ejemplo, si tiene un evento Spin, derivaría una clase SpinEventManager como administrador del evento débil dedicado para el evento. Si el evento existe en más de una clase de origen y, en general, se comporta igual en todas y comparte el mismo tipo de datos de evento, puede utilizarse el mismo administrador para cada una de ellas.

La lista de comprobación de implementación para derivar de la clase WeakEventManager consiste en invalidar dos métodos virtuales y exponiendo diversos miembros más cuyos nombres no se rigen específicamente por una plantilla virtual, pero que debe existir de todos modos. Las invalidaciones se utilizan para iniciar o finalizar el modo de entrega de eventos por la infraestructura de WPF. Los demás miembros son necesarios para proporcionar funcionalidad que permita que sus propias implementaciones de IWeakEventListener puedan utilizar WeakEventManager para asociar agentes de escucha al evento.

Para obtener las notas de implementación detalladas a fin de derivar de WeakEventManager, vea "Notas para los herederos" en el tema de referencia de WeakEventManager.

IWeakEventListener

Una clase que implementa IWeakEventListener tiene una sola responsabilidad: implementar el método de interfaz ReceiveWeakEvent. La implementación de ReceiveWeakEvent debe ser centralizada y dirigir cualquier referencia de evento que exista en esa clase al objeto WeakEventManager adecuado.

Para obtener las notas de implementación detalladas a fin de implementar la interfaz IWeakEventListener, vea "Notas a para los implementadores" en el tema de referencia del método ReceiveWeakEvent.

Asociar agentes de escucha

Supongamos que tiene un evento ClockwiseSpin (definido por Spinner) que es un evento convencional. Si desea utilizar el modelo para este evento, debe usar una clase ClockwiseSpinEventManager existente derivada de WeakEventManager o bien implementarla personalmente. Si tiene una clase de agente de escucha SpinListener que utilizar como agente de escucha, la técnica convencional (sin utilizar el modelo) para asociar el controlador sería emplear la sintaxis +=:

spinnerInstance.ClockwiseSpin += new EventHandler(MyOnCWSpinHandler);

Pero si tiene una clase que implementa IWeakEventListener y que tiene en cuenta el evento ClockwiseSpin y su administrador en la implementación, la sintaxis que debe utilizar en su lugar para el modelo WeakEvent es:

ClockwiseSpinEventManager.AddListener(spinnerInstance, this);

A continuación, la lógica de control del evento se especifica dentro de uno de los casos de la implementación de ReceiveWeakEvent en la clase, no como un controlador basado en delegado convencional.

Implementar el modelo para eventos externos

Un aspecto interesante del modelo WeakEvent es que le permite implementar el modelo con un evento que no forme parte de la base de código. Desde la perspectiva del origen, la manera de asociar los controladores a su evento no varía, y se controla por WeakEventManager. Sólo es necesario definir WeakEventManager para ese evento y, a continuación, tener en cuenta ese evento como parte de la lógica de ReceiveWeakEvent en cualquier agente de escucha probable que utilice el modelo para escuchar ese evento.

Vea también

Conceptos

Información general sobre eventos enrutados

Información general sobre el enlace de datos

Referencia

WeakEventManager

IWeakEventListener