Silverlightの動作のためにondetaching()を自動的に呼び出します
質問
Silverlightコントロールでいくつかのブレンド動作とトリガーを使用しています。コントロールが使用されなくなったときに動作またはトリガーを求めている場合(つまり、視覚ツリーから削除された場合)、ondetaching()が動作またはトリガーを求めることを自動的に分離または保証するメカニズムがあるかどうか疑問に思っています。
私の問題は、動作の1つがあるため、コントロールとマネージドメモリリークがあることです。この動作は、Onattached()Overrideのいくつかの長寿命のオブジェクトのイベントを購読しており、Garbage Collectionの候補になることができるように、Ondetaching()Overrideでそのイベントから登録解除する必要があります。ただし、視覚ツリーからコントロールを削除したときにondetaching()が呼び出されることはありません...私がそれを実現できる唯一の方法は、コントロールを削除する前に問題のある動作を明示的に切り離すことです。 。
今のところ、私の唯一の解決策は、コードビハインドに、ガベージ収集の問題を引き起こす既知の動作を通過して切り離すことができるコントロールのパブリックメソッドを作成することでした。パネルからコントロールを削除する前に、これを呼び出すことを知るのはクライアントコード次第です。私はこのアプローチが本当に好きではないので、私が見落としている、またはより良い提案をしているこれを行う自動的な方法を探しています。
public void DetachBehaviors()
{
foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot))
{
behavior.Detach();
}
//continue detaching all known problematic behaviors on the control....
}
解決
この場合に本当に必要なのは、自動的に分離する方法ではなく、長生きするオブジェクトが保持する参照が動作(したがって、それが参照している他のすべて)がゴミ収集されないようにしないようにすることです。
これは、メディエーターパターンを実装することで痛みます。コンセプトは、長命のオブジェクトにあなたへの参照を含む代表者に与えないということです Behaviour
, 代わりに、仲介者クラスを作成します。メディエーターは長寿命のオブジェクトイベントに取り付けられ、 弱者 行動に。長寿命のオブジェクトがイベントを発射すると、調停者は WeakReference
もしそうなら、イベントを渡すためにそれにメソッドを呼び出すならば、まだ生きています。イベントが発生した場合、メディエーターは WeakReference
もはや生きていないので、イベントハンドラーが長生きしたオブジェクトから剥離します。
したがって、動作を止めるものは何もなく、他のすべてがゴミを集めて収集することから、残ったものはすべて非常に小さなメディエーターインスタンスであり、死んだ参照が長寿命のオブジェクトにまだ取り付けられています。これらのメディエーターは小さいので、彼らは本当の問題を表しておらず、イベントが次に発砲するときにもそれらが消えます。
幸いなことに、自分でこのようなものを構築する必要はありません。それはと呼ばれます WeakEventListener
. 。このブログ: 「弱い」貢献を強調する。拡張により、WeakeventListenerを使用したメモリリークを防ぐことができます! このテーマに関するリンクの優れたセットがあります。
他のヒント
Joost Van Schaik メモリリークの問題を回避しながら、添付の動作から参照をクリーンアップする代替方法を提供します。これは、Associated Objectのロードされていない無負荷イベントの代表者を使用して、クリーンアップ作業を行うことに依存します。
彼はまた、添付の動作のためにスタブを生成するためのコードスニッペットを提供しています。