5

Ich verwende mehrere Blend-Verhalten und Trigger auf einem Silverlight-Steuerelement. Ich frage mich, ob es einen Mechanismus für das automatische Lösen oder Sicherstellen gibt, dass OnDetaching() für ein Verhalten oder einen Auslöser aufgerufen wird, wenn das Steuerelement nicht mehr verwendet wird (d. H. Aus dem visuellen Baum entfernt).Automatisches Aufrufen von OnDetaching() für Silverlight-Verhalten

Mein Problem ist, dass es ein Speicherleck mit der Kontrolle, weil einer der Verhaltensweisen verwaltet wird. Das Verhalten subskribiert ein Ereignis für ein langlebiges Objekt in der OnAttached() - Überschreibung und sollte sich von diesem Ereignis in der OnDetaching() - Überschreibung abmelden, damit es ein Kandidat für die Garbage Collection werden kann. OnDetaching() scheint jedoch nie aufgerufen zu werden, wenn ich das Steuerelement aus dem visuellen Baum entferne. Die einzige Möglichkeit, dies zu erreichen, besteht darin, die problematischen Verhaltensweisen VOR dem Entfernen des Steuerelements explizit zu trennen und dann ordnungsgemäß zu sammeln .

Gerade jetzt meine einzige Lösung war eine öffentliche Methode in dem Code-Behind für die Steuerung zu schaffen, der durch gehen kann, und nehmen Sie alle bekannten Verhaltensweisen, die Garbage Collection zu Problemen führen würde. Es wäre Aufgabe des Client-Codes, dies vor dem Entfernen des Steuerelements aus dem Panel zu erfahren. Ich mag diesen Ansatz nicht wirklich, deshalb suche ich nach einem automatischen Weg, dies zu tun, den ich übersehe oder einen besseren Vorschlag.

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

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

Antwort

3

Was Sie wirklich in diesem Fall brauchen, ist nicht eine Möglichkeit, automatisch zu lösen, sondern um sicherzustellen, dass die durch die lange gelebt Objekt gehalten Referenz das Verhalten nicht halten (und damit alles andere hat es einen Verweis auf) aus Müll gesammelt werden.

Dies wird erreicht, indem ein Mediator-Muster implementiert wird. Das Konzept ist, dass Sie dem langlebigen Objekt keinen Delegierten mit einer Referenz auf Ihre Behaviour geben, stattdessen erstellen Sie eine Mediator-Klasse als Vermittler. Der Mediator wird an das Ereignis langlebiger Objekte angehängt und enthält eine WeakReference für das Verhalten. Wenn das langlebige Objekt das Ereignis auslöst, überprüft der Mediator, ob WeakReference noch aktiv ist, wenn dies der Fall ist, wird eine Methode aufgerufen, um das Ereignis weiterzuleiten. Wenn der Mediator beim Auftreten des Ereignisses feststellt, dass WeakReference nicht mehr aktiv ist, löst er seinen Ereignishandler vom langlebigen Objekt.

Daher gibt es nichts, was das Verhalten stoppt und alles andere daran beteiligt wäre, Müll gesammelt zu werden. Alles, was übrig bleibt, ist eine sehr kleine Vermittlerinstanz mit einem toten Verweis, der immer noch an das langlebige Objekt angehängt ist. Da diese Mediatoren winzig sind, stellen sie kein echtes Problem dar und selbst diese verschwinden beim nächsten Mal, wenn das Ereignis ausgelöst wird.

Zum Glück müssen Sie nicht über diese Sachen selbst andere haben es bereits getan bauen. Es heißt WeakEventListener. Dieser Blog: Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier! hat eine ausgezeichnete Reihe von Links zu dem Thema.

3

Joost van Schaik bietet eine alternative Möglichkeit, Referenzen von angeschlossenen Verhaltensweisen zu bereinigen, während das Problem mit dem Speicherverlust zu vermeiden. Es hängt davon ab, die Aufräumarbeiten mit Delegaten der Ereignisse Loaded und Unloaded des AssociatedObject durchzuführen.

Er bietet auch einen Code-Schnipsel für Stubs für angebracht Verhalten zu erzeugen.

+0

Danke! Dieser Ansatz hat gut für unsere Bedürfnisse funktioniert. – Jaans