Desechar los controles de usuario de WPF

Creé un control de usuario WPF personalizado que está destinado a ser utilizado por un tercero. Mi control tiene un miembro privado que es desechable, y me gustaría asegurar que siempre se llame a su método de eliminación una vez que se cierre la ventana / aplicación que lo contiene. Sin embargo, UserControl no es desechable. Intenté implementar la interfaz IDisposable y suscribirme al evento descargado, pero ninguno se llama cuando la aplicación anfitriona se cierra. Si es posible, no quiero depender de los consumidores de mi control que recuerden llamar a un método específico de Disposición.

public partial class MyWpfControl : UserControl { SomeDisposableObject x; // where does this code go? void Somewhere() { if (x != null) { x.Dispose(); x = null; } } } 

La única solución que he encontrado hasta ahora es suscribirme al evento ShutdownStarted del Dispatcher. ¿Es este un enfoque razonable?

 this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; 

Interesante entrada de blog aquí:

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

Menciona la suscripción a Dispatcher_ShutDownStarted para disponer de sus recursos.

Dispatcher.ShutdownStarted evento Dispatcher.ShutdownStarted se activa solo al final de la aplicación. Vale la pena llamar a la lógica de eliminación justo cuando el control deja de usarse. En particular, libera recursos cuando el control se usa muchas veces durante el tiempo de ejecución de la aplicación. Entonces, la solución de ioWint es preferible. Aquí está el código:

 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 }; } 

Tienes que tener cuidado con el destructor. Esto se invocará en el hilo del Finalizador de GC. En algunos casos, los recursos que su liberación pueden no gustar se liberan en un hilo diferente del que se crearon.

Uso el siguiente Comportamiento de interactividad para proporcionar un evento de descarga a WPF UserControls. Puede incluir el comportamiento en UserControls XAML. Para que pueda tener la funcionalidad sin colocar la lógica en cada UserControl.

Declaración XAML:

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

Manejador de CodeBehind:

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

Código de conducta:

 ///  /// 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); } } 

Mi escenario es un poco diferente, pero la intención es la misma. Me gustaría saber cuándo se cierra / cierra la ventana principal que aloja mi control de usuario, ya que la vista (es decir, mi control de usuario) debe invocar a los presentadores en closeView para ejecutar algunas funciones y realizar tareas de limpieza. (Bueno, estamos implementando un patrón MVP en una aplicación PRISM de WPF).

Me di cuenta de que en el evento Loaded del usercontrol, puedo conectar mi método ParentWindowClosing al evento Parent closing Closing. ¡De esta manera, mi Usercontrol puede estar al tanto cuando la ventana principal se cierra y actúa en consecuencia!

Estoy pensando que la descarga se llama todo pero existe en 4.7. Pero, si está jugando con versiones anteriores de .Net, intente hacerlo en su método de carga:

 e.Handled = true; 

No creo que las versiones anteriores se descarguen hasta que se maneje la carga. Solo publico porque veo que otros siguen haciendo esta pregunta, y no he visto esta propuesta como una solución. Solo toco .Net varias veces al año y me encontré con esto unos años atrás. Pero, me pregunto si es tan simple como descargar no se ha llamado hasta que la carga haya terminado. Parece que funciona para mí, pero de nuevo en .Net más reciente parece que siempre se descarga, incluso si la carga no está marcada como manejada.

Un UserControl tiene un Destructor, ¿por qué no lo usas?

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