21

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

WPFでは、話はそれほど単純ではありません。私はこれを数時間検索し、2つの基本的なテーマに遭遇しました。

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

次に、Dispatcher.ShutdownStartedへの参照がいくつか見つかりました。ShutdownStartedイベントを使用しようとしましたが、すべてのコントロールで起動するわけではないようです。ShutdownStartedのハンドラーを実装したWPFUserControlがたくさんありますが、呼び出されることはありません。Windowsでのみ機能するのか、それともWPFAppクラスでのみ機能するのかわかりません。ただし、正しく起動されておらず、アプリを閉じるたびに開いているPerformanceCounterオブジェクトがリークしています。

Dispatcher.ShutdownStartedイベントよりも、管理されていないリソースをクリーンアップするためのより良い代替手段はありますか?Disposeが呼び出されるようにIDisposableを実装するためのトリックはありますか?可能な限り、ファイナライザーの使用は避けたいと思います。

4

5 に答える 5

13

Dispatcher.ShutdownStartedは、実際にはWPFがUserControlsのリソースを破棄するために提供する唯一のメカニズムのようです。(私がしばらく前に尋ねた非常によく似た質問を参照してください)。

この問題に取り組むもう1つの方法は、すべての使い捨てリソース(可能な場合)をコードの背後から別のクラス(MVVMパターンを使用する場合のViewModelなど)に移動することです。次に、より高いレベルで、メインウィンドウのクローズを処理し、Messengerクラスを介してすべてのViewModelに通知できます。

Dispatcher.ShutdownStartedイベントが表示されないことに驚いています。その時点で、UserControlsはトップレベルウィンドウに接続されていますか?

于 2009-10-11T13:16:59.573 に答える
11

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

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

于 2009-10-11T16:05:35.910 に答える
8

私もこれを探していて、さまざまなオプションをテストした後、ベネチアのソリューションを実装しました

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

        base.OnVisualParentChanged(oldParent);
    }

Children.Clear()親がMethodを呼び出し、すでに子にアイテムが追加されている場合、DependencyObjectに値があることに気付きました。しかし、親がアイテム(Children.Add(CustomControl))を追加し、子が空の場合、DependencyObjectはnullでした。

于 2012-12-28T18:36:50.880 に答える
0

他の人がこの問題について本当に役立つ情報を提供してくれましたが、IDisposableがない理由について多くのことを説明する、あなたが持っていないかもしれない情報が少しあります。基本的に、WPF(およびSilverlight)はWeakReferencesを多用します。これにより、GCが引き続き収集できるオブジェクトを参照できます。

于 2009-10-11T20:53:41.600 に答える
0

IDbConnection実装ドライバーまたはEntityFrameworkを使用してデータベースへの接続を使用した場合、これは困難です。

これらの場合、変更/トランザクションを追跡できるように、ウィンドウごとに1つのオブジェクト接続/コンテキストを維持することをお勧めします。(リンク

だから私はOnClosingをオーバーライドしました:

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
      base.OnClosing(e);
      this._context.Dispose();
}

コンテキストは、リソースをクリーンアップするためにIDisposableを実装する私のViewModel/Controlにすることができます。

リソースを破棄するためのOnClosingの使用例(リンク

于 2020-10-28T14:31:56.527 に答える