2009-10-11 9 views
20

私はWPFには比較的新しいので、いくつかのことは私にとってはかなり外国語です。 1つは、Windowsフォームとは異なり、WPFコントロール階層はIDisposableをサポートしていません。 Windowsフォームでは、ユーザーコントロールが管理対象リソースを使用した場合、すべてのコントロールが実装したDisposeメソッドをオーバーライドすることで、リソースを簡単にクリーンアップすることができました。WPFユーザーコントロールの適切なクリーンアップ

WPFでは、その話は単純ではありません。

最初のテーマは、WPFコントロールに管理されていないリソースがないため、WPFでIDisposableが実装されていないことを明示しています。それは事実かもしれませんが、WPFクラス階層へのユーザー拡張が本当に管理されたリソースを(直接的または間接的にモデルを通じて)使用するかもしれないという事実を完全に見逃したようです。 IDisposableを実装しないことにより、Microsoftは、カスタムWPFコントロールまたはウィンドウで使用されるアンマネージリソースをクリーンアップできる唯一の保証されたメカニズムを効果的に削除しました。

次に、Dispatcher.ShutdownStartedへの参照がいくつか見つかりました。 ShutdownStartedイベントを使用しようとしましたが、すべてのコントロールで起動するようには見えません。私はShutdownStarted用のハンドラを実装したWPF UserControlの束を持っていて、決して呼び出されません。私はそれがWindows、またはおそらくWPF Appクラスのためにのみ動作するかどうかはわかりません。しかし、それは適切に発射されていない、私は開いているPerformanceCounterのオブジェクトは、アプリケーションが終了するたびに漏れている。

Dispatcher.ShutdownStartedイベントよりもアンマネージリソースをクリーンアップする方がよいでしょうか? Disposeが呼び出されるようにIDisposableを実装するにはいくつかのトリックがありますか?可能であれば、ファイナライザを使用してを避けることをお勧めします。を避けてください。

答えて

12

Dispatcher.ShutdownStartedが実際には、WPFがUserControlsのリソースを処分するために提供する唯一のメカニズムであるように思えます。 (ちょっと前に尋ねたsimilar questionをご覧ください)。

問題を解決する別の方法は、可能な限り、すべての使い捨てリソースを、コードの背後に別のクラス(MVVMパターンを使用する場合はViewModelなど)に移動することです。その後、メインウィンドウを閉じて、Messengerクラスを介してすべてのViewModelに通知することができます。

Dispatcher.ShutdownStartedイベントが表示されないのは驚きです。あなたのUserControlsは、その時点でトップレベルウィンドウにアタッチされていますか?

+4

コードビハインドから使い捨てリソースを移動するための+1。 WPFの重要な学習ポイントの1つは、データバインディングアーキテクチャの強みと表現力を活用するためにコードビハインドを最小限に抑えることです。学習するのは痛いことです(学習曲線は崖に登るようなものですが)WPFの考え方を「取得」するときには報酬を与えます。 –

+0

すべての使い捨てリソースは実際にはViewModelにあり、それ自体はIDisposableです。 Dispatcher.ShutdownStartedイベントが発生していない理由について、私は本当に混乱しています。パフォーマンスカウンターコントロール(および関連するViewModel)は、に埋め込まれているため、WPFグラフに実際に添付されています。 – jrista

+1

@Greg D:私は一般的にWPFモデルを取得します。私はWPFの基礎を習得するとすぐにMVVMを使い始めました。私のCodeBehindは、基本的なコンストラクタとInitializeComponentへの呼び出しという単純なものです。 WPFの合成機能とデータバインディング機能は素晴らしいものではありません。選択肢があれば、Windowsフォームに戻ることはありません。 – jrista

9

IDisposableインターフェイスは、Winformsとはメカニズムが異なるため、WPFでは(ほとんど)意味がありません。 WPFでは、ビジュアルで論理的なツリーを覚えておく必要があります。それは基本的なことです。
したがって、ビジュアルオブジェクトは、通常、他のオブジェクトの子として存在します。 WPF構築メカニズムの基盤は、ビジュアルオブジェクトを階層的にアタッチし、それが有用でないときには切り離して破棄することです。

UIElementから公開されているOnVisualParentChangedメソッドがチェックされている可能性があります。このメソッドは、ビジュアルオブジェクトがアタッチされているときと、デタッチされているときに呼び出されます。これは、管理されていないオブジェクト(ソケット、ファイルなど)を処分する適切な場所になる可能性があります。

+0

OnVisualParentChangedについてのヒントをありがとう。私はそれで遊んで、私の問題を解決するのに役立つかどうかを見てみましょう。 – jrista

0

他にもこの問題に関する有用な情報がありますが、IDisposableが存在しない理由について多く説明してくれる情報はありません。基本的に、WPF(とSilverlight)はWeakReferencesを大量に使用します。これにより、GCが引き続き収集できるオブジェクトを参照できます。

私もこれを探していたと私はベネチア

protected override void OnVisualParentChanged(DependencyObject oldParent) 
    { 
     if (oldParent != null) 
     { 
      MyOwnDisposeMethod(); //Release all resources here 
     } 

     base.OnVisualParentChanged(oldParent); 
    } 

のソリューションを実装し貴様のオプションをテストした後、私はその親の呼び出しChildren.Clear()方法を実現し、すでに項目が子供に追加した、DependencyObjectが値を持っていた。

+0

洞察に感謝ピート。私はあなたがこれをより詳細に説明するいくつかのリンクを持っていれば興味がありますか? WeakReferencesの重い使用が問題を引き起こさないかどうか不思議です。彼らはニッチな状況で強力なツールになることができます...しかし、私はそれらがWPFでどのように使われているのか想像できません。 – jrista

5

しかし、親が項目(Children.Add(CustomControl))を追加し、子が空になったときにDependencyObjectがnullでした。

+0

if(Parent == null)に変更しました。コントロールを別のコンテナに移動すると、自己破棄されません。 – Sean

関連する問題