5

J'utilise plusieurs comportements Blend et triggers sur un contrôle Silverlight. Je me demande s'il existe un mécanisme pour se détacher automatiquement ou s'assurer que OnDetaching() est appelé pour un comportement ou un déclencheur lorsque le contrôle n'est plus utilisé (c'est-à-dire retiré de l'arborescence visuelle).Appel automatique de OnDetaching() pour les comportements Silverlight

Mon problème est qu'il y a une fuite de mémoire gérée avec le contrôle en raison de l'un des comportements. Le comportement s'abonne à un événement sur un objet de longue durée dans le remplacement OnAttached() et devrait se désabonner de cet événement dans le remplacement OnDetaching() afin qu'il puisse devenir un candidat pour la récupération de place. Cependant, OnDetaching() ne semble jamais être appelé quand je supprime le contrôle de l'arbre visuel ... la seule façon de le faire est de détacher explicitement les comportements problématiques AVANT de retirer le contrôle et ensuite il est correctement ramassé .

À l'heure actuelle, ma seule solution était de créer une méthode publique dans le code-behind pour le contrôle qui peut passer par et déconnecter tous les comportements connus qui causeraient des problèmes de récupération de place. Il appartiendrait au code client de savoir appeler cela avant de retirer le contrôle du panneau. Je n'aime pas vraiment cette approche, donc je suis à la recherche d'une façon automatique de faire cela que je néglige ou une meilleure suggestion.

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

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

Répondre

3

Qu'est-ce que vous avez vraiment besoin dans ce cas n'est pas un moyen de se détacher automatiquement, mais pour assurer que la référence détenue par l'objet à vie longue ne garde pas le comportement (et donc tout le reste, il a une référence à) de être ramassé des ordures. Ceci est obtenu en implémentant un motif Mediator. Le concept est que vous ne donnez pas à l'objet de longue durée un délégué avec une référence à votre Behaviour, mais que vous créez une classe Mediator comme intermédiaire. Le médiateur se rattache à l'événement Objets à vie longue et contient un WeakReference au comportement. Lorsque l'objet de longue durée déclenche l'événement, le médiateur vérifie que le WeakReference est toujours actif, si tel est le cas, il appelle une méthode pour transmettre l'événement. Si, lorsque l'événement se produit, le médiateur constate que le WeakReference n'est plus actif, il détache son gestionnaire d'événements de l'objet à vie longue.

Par conséquent, il n'y a rien qui empêche le comportement et tout le reste impliqué d'être collecté tout ce qui reste est une très petite instance de médiateur avec une référence morte encore attachée à l'objet de longue durée. Puisque ces médiateurs sont minuscules, ils ne représentent pas un réel problème et même ceux-ci disparaîtront la prochaine fois que l'événement se déclenchera.

Heureusement, vous n'avez pas à construire vous-même ce matériel, d'autres l'ont déjà fait. C'est ce qu'on appelle le WeakEventListener. Ce blog: Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier! a un excellent ensemble de liens sur le sujet.

3

Joost van Schaik offre une alternative pour nettoyer les références des comportements attachés, tout en évitant le problème avec la fuite de mémoire. Cela dépend de faire le travail de nettoyage en utilisant les délégués des événements Loaded et Unloaded de l'AssociatedObject.

Il propose également un extrait de code pour générer des stubs pour les comportements attachés.

+0

Merci! Cette approche a bien fonctionné pour nos besoins. – Jaans