WPF-Benutzersteuerelemente bereitstellen

Ich habe ein benutzerdefiniertes WPF-Benutzersteuerelement erstellt, das von Dritten verwendet werden soll. Meine Kontrolle hat ein privates Mitglied, das wegwerfbar ist, und ich möchte sicherstellen, dass seine Entsorgungsmethode immer aufgerufen wird, sobald das enthaltende Fenster / die Anwendung geschlossen wird. UserControl ist jedoch nicht verfügbar. Ich habe versucht, die IDisposable-Schnittstelle zu implementieren und das Unloaded-Ereignis zu abonnieren, aber beide werden nicht aufgerufen, wenn die Host-Anwendung geschlossen wird. Wenn es möglich ist, möchte ich mich nicht darauf verlassen, dass die Konsumenten meiner Kontrolle sich erinnern, 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, besteht darin, das ShutdownStarted-Ereignis des Dispatchers zu abonnieren. Ist das ein vernünftiger Ansatz?

 this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; 

   

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 abonniert haben, um Ihre Ressourcen zu entsorgen.

Dispatcher.ShutdownStarted Ereignis Dispatcher.ShutdownStarted wird nur am Ende der Anwendung ausgetriggers. Es lohnt sich, die Dispositionslogik sofort aufzurufen, wenn die Kontrolle außer Betrieb ist. Insbesondere werden Ressourcen freigegeben, wenn die Steuerung während der Laufzeit der Anwendung mehrmals verwendet wird. Daher ist die ioWint -Lösung 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 }; } 

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

Ich verwende das folgende Interactivity Behavior, um WPF UserControls ein Entladeereignis bereitzustellen. Sie können das Verhalten in das UserControls-XAML einschließen. So können Sie die functionalität haben, ohne die Logik in jedem einzelnen Benutzersteuerelement zu platzieren.

XAML-Deklaration:

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

CodeBehind-Handler:

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

Verhaltenscode:

 ///  /// This behavior raises an event when the containing window of a  is closing. ///  public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior { 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; } ///  /// Registers to the containing windows Closing event when the UserControl is loaded. ///  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; } ///  /// The containing window is closing, raise the UserControlClosing event. ///  private void WindowClosingHandler(object sender, CancelEventArgs e) { OnUserControlClosing(); } ///  /// This event will be raised when the containing window of the associated  is closing. ///  public event EventHandler UserControlClosing; protected virtual void OnUserControlClosing() { var handler = UserControlClosing; if (handler != null) handler(this, EventArgs.Empty); } } 

Mein Szenario ist ein wenig anders, aber die Absicht ist dieselbe, die ich gerne wissen würde, wenn das Elternfenster, das mein Benutzersteuerelement hostet, geschlossen / geschlossen wird. Die Ansicht (dh meine Benutzersteuerung) sollte die Präsentatoren oncloseView aufrufen, um einige functionen auszuführen und Aufräumarbeiten durchzuführen. (Nun, wir implementieren ein MVP-Muster in einer WPF PRISM-Anwendung).

Ich habe gerade festgestellt, dass ich im Loaded-Ereignis des Benutzersteuerelements meine ParentWindowClosing-Methode mit dem Closing-Ereignis des übergeordneten Windows verbinden kann. Auf diese Weise kann meine Benutzerkontrolle erkennen, wenn das Elternfenster geschlossen wird, und entsprechend handeln!

Ich denke, Entladen wird alles genannt, aber in 4.7 ist es schwer. Wenn Sie jedoch mit älteren Versionen von .NET experimentieren, versuchen Sie dies in Ihrer Lade-Methode:

 e.Handled = true; 

Ich glaube nicht, dass ältere Versionen entladen werden, bis das Laden erledigt ist. Ich poste nur, weil ich sehe, dass andere immer noch diese Frage stellen, und habe dies nicht als Lösung gesehen. Ich berühre nur ein paar Mal im Jahr .Net und bin vor ein paar Jahren dazu gekommen. Aber ich frage mich, ob es so einfach ist wie Entladen nicht aufgerufen zu werden, bis das Laden beendet ist. Scheint wie es für mich funktioniert, aber wieder in neueren .Net scheint es immer unload aufzurufen, auch wenn das Laden nicht als behandelt markiert ist.

Ein UserControl hat einen Destruktor, warum benutzt du das nicht?

 ~MyWpfControl() { // Dispose of any Disposable items here }