5

Estoy usando varios comportamientos y activadores de mezcla en un control Silverlight. Me pregunto si hay algún mecanismo para separar automáticamente o asegurar que OnDetaching() se llame para un comportamiento o desencadenar cuando el control ya no se usa (es decir, eliminado del árbol visual).Llamada automática OnDetaching() para Comportamientos de Silverlight

Mi problema es que hay una pérdida de memoria administrada con el control debido a uno de los comportamientos. El comportamiento se suscribe a un evento en algún objeto de larga duración en la anulación OnAttached() y debe anular su suscripción de ese evento en la anulación OnDetaching() para que pueda convertirse en un candidato para la recolección de elementos no utilizados. Sin embargo, nunca parece que se llame a OnDetaching() cuando elimino el control del árbol visual ... la única manera en que puedo lograr que ocurra es separando explícitamente los comportamientos problemáticos ANTES de quitar el control y luego es correctamente recolectada. .

En este momento mi única solución era crear un método público en el código subyacente para el control que puede pasar y desconectar los comportamientos conocidos que podrían causar problemas de recolección de basura. Depende del código del cliente saber llamar esto antes de quitar el control del panel. Realmente no me gusta este enfoque, por lo que estoy buscando una manera automática de hacer esto que estoy pasando por alto o una mejor sugerencia.

public void DetachBehaviors() 
{ 
    foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot)) 
    { 
      behavior.Detach(); 
    } 

    //continue detaching all known problematic behaviors on the control.... 
} 

Respuesta

3

Lo que realmente necesita en este caso no es una manera de separar de forma automática, sino garantizar que la referencia contenida en el objeto de larga vida no mantener el comportamiento (y por lo tanto todo lo demás que tiene una referencia a) a partir de siendo basura recolectada.

Esto se logra implementando un patrón Mediator. El concepto es que no le das un delegado a un objeto de larga duración con una referencia a tu Behaviour, sino que creas una clase Mediator como intermediario. El mediador se conecta al evento de objetos de larga vida y tiene un WeakReference al comportamiento. Cuando el objeto de larga duración activa el evento, el mediador comprueba que el WeakReference aún está activo, de ser así llama a un método para pasar el evento. Si cuando ocurre el evento, el mediador descubre que el WeakReference ya no está vivo, separa su manejador de eventos del objeto de larga duración.

Por lo tanto, no hay nada que detenga el comportamiento y todo lo demás involucrado por ser basura recolectada, todo lo que queda es una pequeña instancia de mediador con una referencia muerta aún asociada al objeto de larga vida. Dado que estos mediadores son pequeños, no representan un problema real e incluso esos desaparecerán la próxima vez que se desate el evento.

Afortunadamente no tienes que construir esto tú mismo, otros ya lo han hecho. Se llama WeakEventListener. Este blog: Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier! tiene un excelente conjunto de enlaces sobre el tema.

3

Joost van Schaik ofrece una forma alternativa de limpiar las referencias de los comportamientos adjuntos, al tiempo que se evita el problema con la pérdida de memoria. Depende de realizar el trabajo de limpieza utilizando delegados de los eventos Cargados y Descargados del AssociatedObject.

También ofrece un fragmento de código para generar stubs para comportamientos adjuntos.

+0

Gracias! Este enfoque funcionó bien para nuestras necesidades. – Jaans

Cuestiones relacionadas