webentwicklung-frage-antwort-db.com.de

WPF-Benutzersteuerelemente entsorgen

Ich habe ein benutzerdefiniertes WPF-Benutzersteuerelement erstellt, das von Dritten verwendet werden soll. Mein Steuerelement hat ein privates Mitglied, das verfügbar ist, und ich möchte sicherstellen, dass seine Dispose-Methode immer aufgerufen wird, sobald das enthaltende Fenster/die enthaltende Anwendung geschlossen wird. UserControl ist jedoch nicht verfügbar. Ich habe versucht, die IDisposable-Schnittstelle zu implementieren und das Unloaded-Ereignis zu abonnieren, aber keine wird aufgerufen, wenn die Host-Anwendung geschlossen wird. Wenn möglich, möchte ich mich nicht darauf verlassen, dass Verbraucher meiner Kontrolle daran denken, eine bestimmte Dispose-Methode aufzurufen.

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

     // where does this code go?
     void Somewhere() 
     {
         if (x != null)
         {
             x.Dispose();
             x = null;
         }

     }
 }

Die einzige Lösung, die ich bisher gefunden habe, ist das Abonnieren des ShutdownStarted-Ereignisses des Dispatchers. Ist das ein vernünftiger Ansatz?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
114
Mark Heath

Interessanter Blogbeitrag hier:

http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx

Es wird erwähnt, dass Sie Dispatcher.ShutdownStarted abonnieren, um Ihre Ressourcen zu entsorgen.

56
Ray Booysen

Dispatcher.ShutdownStarted Ereignis wird nur am Ende der Anwendung ausgelöst. Es lohnt sich, die Entsorgungslogik nur dann aufzurufen, wenn die Steuerung außer Betrieb ist. Insbesondere werden Ressourcen freigesetzt, wenn die Steuerung zur Laufzeit der Anwendung häufig verwendet wird. Also ist die Lösung von ioWint vorzuziehen. Hier ist der Code:

public MyWpfControl()
{
     InitializeComponent();
     Loaded += (s, e) => { // only at this point the control is ready
         Window.GetWindow(this) // get the parent window
               .Closing += (s1, e1) => Somewhere(); //disposing logic here
     };
}
35
Ilia Barahovski

Sie müssen vorsichtig mit dem Destruktor sein. Dies wird im GC Finalizer-Thread aufgerufen. In einigen Fällen werden die Ressourcen, die Sie freigeben möchten, möglicherweise nicht in einem anderen Thread freigegeben als dem, in dem sie erstellt wurden.

14
Ade Miller

Ich verwende das folgende Interaktivitätsverhalten, um WPF UserControls ein Entladeereignis bereitzustellen. Sie können das Verhalten in die UserControls-XAML aufnehmen. So können Sie die Funktionalität haben, ohne die Logik in jedem einzelnen UserControl zu platzieren.

XAML-Deklaration:

xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"

<i:Interaction.Behaviors>
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>

CodeBehind-Handler:

private void UserControlClosingHandler(object sender, EventArgs e)
{
    // to unloading stuff here
}

Verhaltenscode:

/// <summary>
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing.
/// </summary>
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl>
{
    protected override void OnAttached()
    {
        AssociatedObject.Loaded += UserControlLoadedHandler;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.Loaded -= UserControlLoadedHandler;
        var window = Window.GetWindow(AssociatedObject);
        if (window != null)
            window.Closing -= WindowClosingHandler;
    }

    /// <summary>
    /// Registers to the containing windows Closing event when the UserControl is loaded.
    /// </summary>
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e)
    {
        var window = Window.GetWindow(AssociatedObject);
        if (window == null)
            throw new Exception(
                "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used."
                    .FormatWith(AssociatedObject.GetType().Name));

        window.Closing += WindowClosingHandler;
    }

    /// <summary>
    /// The containing window is closing, raise the UserControlClosing event.
    /// </summary>
    private void WindowClosingHandler(object sender, CancelEventArgs e)
    {
        OnUserControlClosing();
    }

    /// <summary>
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing.
    /// </summary>
    public event EventHandler UserControlClosing;

    protected virtual void OnUserControlClosing()
    {
        var handler = UserControlClosing;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }
}
10
alex.enjoy

Mein Szenario ist ein wenig anders, aber die Absicht ist die gleiche. Ich möchte wissen, wann das übergeordnete Fenster, in dem sich mein Benutzersteuerelement befindet, geschlossen wird. Die Ansicht (d. H. Meine Benutzersteuerung) sollte die Moderatoren von oncloseView aufrufen, um einige Funktionen auszuführen und eine Bereinigung durchzuführen. (Nun, wir implementieren ein MVP-Muster in einer WPF PRISM-Anwendung).

Ich habe gerade herausgefunden, dass ich im Loaded-Ereignis der Benutzersteuerung meine ParentWindowClosing-Methode mit dem Parent-Windows-Closing-Ereignis verbinden kann. Auf diese Weise kann meine Benutzersteuerung erkennen, wann das übergeordnete Fenster geschlossen wird, und entsprechend handeln!

5
ioWint

Ich denke, Entladen heißt in 4.7 alles andere als schwer zu existieren. Wenn Sie jedoch mit älteren Versionen von .Net herumspielen, versuchen Sie dies in Ihrer Lademethode:

e.Handled = true;

Ich glaube nicht, dass ältere Versionen entladen werden, bis das Laden erledigt ist. Einfach posten, weil ich sehe, dass andere diese Frage immer noch stellen und dies nicht als Lösung vorgeschlagen haben. Ich berühre .Net nur ein paar Mal im Jahr und bin vor ein paar Jahren darauf gestoßen. Aber ich frage mich, ob es so einfach ist, wie Unload erst dann aufzurufen, wenn das Laden abgeschlossen ist. Scheint so, als würde es bei mir funktionieren, aber in neueren .Net-Versionen scheint es immer "entladen" zu heißen, auch wenn das Laden nicht als erledigt markiert ist.

0
Michael