1

カスタム コントロールが生成する可能性のあるアンマネージ リソースをクリーンアップする良い方法を見つけようとしています。このシナリオでは、親ウィンドウが、アンマネージ リソースを含むカスタム コントロールを持つ子ウィンドウを開きます (以下のコードを参照)。これらのリソースは、CustomControl が使用されなくなったとき、つまり、それが含まれているツリーがアンロードされたとき (子ウィンドウが閉じたとき)、またはツリーから削除されたとき (つまり、それ自体がアンロードされたとき) にクリーンアップする必要があります。

方法 1 : Unloaded イベント これは、子ウィンドウを手動で閉じたときにトリガーされますが、親ウィンドウを閉じた場合にはトリガーされません (その後、子ウィンドウが自動的に閉じられます)。

メソッド 2 : OnVisualChildrenChanged これは、子ウィンドウが親によって手動または自動で閉じられたときに呼び出されず、CustomControl が別の親要素に移動された場合にのみ使用されます。

方法 3 : Dispatcher.ShutdownStarted ユーザーがアプリを終了する前にいくつかの子ウィンドウを開いたり閉じたりした可能性があり、そのメモリを最後にクリーンアップするだけでは十分ではないため、これはあまり役に立ちません。

方法 4 : CustomControl を ChildWindow.Closing にサブスクライブさせる これも十分ではありません.. コントロールはウィンドウ内にあることを認識する必要はありません。

方法 5 : ファイナライザー が方法 3 と同じ問題に悩まされる.. 呼び出されるまでに時間がかかる可能性がある

public class CustomControlWithManagedResources : Control
{
    ~CustomControlWithManagedResources()
    {
        Console.WriteLine("~CustomControlWithManagedResources");
    }

    public CustomControlWithManagedResources()
    {
        Unloaded += CustomControl_Unloaded;
        Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
    }

    void Dispatcher_ShutdownStarted(object sender, EventArgs e)
    {
        Console.WriteLine("ShutdownStarted");
    }

    void CustomControl_Unloaded(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("Unloaded");
    }

    protected override void OnVisualParentChanged(DependencyObject oldParent)
    {
        base.OnVisualParentChanged(oldParent);

        if(oldParent != null)
            Console.WriteLine("OnVisualParentChanged");
    }
}

public class ChildWindow : Window
{
    public ChildWindow()
    {
        Content = new CustomControlWithManagedResources();
    }
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
    {
        base.OnMouseDoubleClick(e);
        new ChildWindow() { Owner = this }.Show();
    }
}
4

2 に答える 2

2

WPF アプリケーションでこれを行う正しい方法は、MVVMパターンを使用し、すべてのロジックと依存関係をビュー (コントロール) からビューモデルに削除することです。

親ViewModelは、実装された子ViewModelを作成し、子ViewModelをIDisposable削除すると、子ViewModelを呼び出しますDispose

メインの ViewModel にクリーンアップが必要な管理されていないリソースがある場合は、それを実装IDisposableし、それを作成するブートストラッパーがそれらのクリーンアップを担当する必要があります。

もう 1 つの参考資料はCaliburn.Microです。

于 2014-04-21T15:44:12.937 に答える
1

Closing イベントを求めているようです。

これを見てください:

http://msdn.microsoft.com/en-us/library/system.windows.window_events(v=vs.110).aspx

ウィンドウが閉じると、Closing と Closed の 2 つのイベントが発生します。

ウィンドウは、非クライアント領域とクライアント領域で提供されるメカニズムによって明示的に閉じることができますが、次のようなアプリケーションまたは Windows の他の部分での動作の結果として、ウィンドウを暗黙的に閉じることもできます。

ユーザーが Windows をログオフまたはシャットダウンします。

ウィンドウの所有者が閉じます (所有者を参照してください)。

メイン アプリケーション ウィンドウは閉じられ、ShutdownMode は OnMainWindowClose です。

シャットダウンが呼び出されます。

これらすべてのシナリオで、Closing および Close イベントが呼び出されます。

コントロールを Window.Closing イベントにサブスクライブしないでください。ウィンドウに仕事をさせてください。

于 2014-04-21T09:35:43.763 に答える