Smaltimento dei controlli utente WPF

Ho creato un controllo utente WPF personalizzato che è destinato ad essere utilizzato da una terza parte. Il mio controllo ha un membro privato che è usa e getta, e mi piacerebbe assicurarmi che il suo metodo di eliminazione venga sempre chiamato una volta chiusa la finestra o l’applicazione contenente. Tuttavia, UserControl non è usa e getta. Ho provato a implementare l’interfaccia IDisposable e ad iscrivermi all’evento Unloaded, ma nessuno dei due viene chiamato quando l’applicazione host si chiude. Se ansible, non voglio fare affidamento sui consumatori del mio controllo ricordando di chiamare un metodo Dispose specifico.

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

L’unica soluzione che ho trovato finora è iscriversi all’evento ShutdownStarted del Dispatcher. È un approccio ragionevole?

 this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; 

Post interessante sul blog qui:

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

Indica di iscriverti a Dispatcher_ShutDownStarted per disporre delle tue risorse.

Dispatcher.ShutdownStarted evento Dispatcher.ShutdownStarted viene generato solo alla fine dell’applicazione. Vale la pena di chiamare la logica di smaltimento proprio quando il controllo diventa inutilizzabile. In particolare, libera le risorse quando il controllo viene utilizzato più volte durante il runtime dell’applicazione. Quindi la soluzione di ioWint è preferibile. Ecco il codice:

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

Devi stare attento ad usare il distruttore. Questo verrà chiamato sul thread di GC Finalizer. In alcuni casi, le risorse a cui la tua liberazione potrebbe non piacere vengono pubblicate su un thread diverso da quello in cui sono state create.

Io utilizzo il seguente comportamento di interattività per fornire un evento di scarico a UserControls di WPF. È ansible includere il comportamento in UserControls XAML. Quindi puoi avere la funzionalità senza posizionarla in ogni singolo UserControl.

Dichiarazione XAML:

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

Gestore CodeBehind:

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

Codice di comportamento:

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

Il mio scenario è leggermente diverso, ma l’intento è lo stesso che vorrei sapere quando la finestra genitore che ospita il mio controllo utente è chiusa / chiusa come La vista (cioè il mio usercontrol) dovrebbe invocare i relatori oncloseView per eseguire alcune funzionalità ed eseguire la pulizia. (beh stiamo implementando un pattern MVP su un’applicazione PRISM WPF).

Ho appena capito che nell’evento Loaded di usercontrol, posso colbind il mio metodo ParentWindowClosing all’evento Closing windows Parent. In questo modo il mio Usercontrol può essere consapevole quando la finestra Genitore viene chiusa e agisce di conseguenza!

Sto pensando che lo scaricamento è chiamato tutto ma a dura esistono in 4.7. Ma, se stai giocando con versioni precedenti di .Net, prova a farlo nel tuo metodo di caricamento:

 e.Handled = true; 

Non penso che le versioni precedenti scaricheranno fino a quando il caricamento non verrà gestito. Pubblicare solo perché vedo che gli altri continuano a fare questa domanda e non ho visto questa proposta come una soluzione. Tocco solo .Net alcune volte all’anno, e mi sono imbattuto in questo qualche anno fa. Ma, mi chiedo se è semplice come scaricare non essere chiamato fino a quando il caricamento non è finito. Sembra che funzioni per me, ma di nuovo in .Net sembra sempre chiamare scarica anche se il caricamento non è contrassegnato come gestito.

Un UserControl ha un Destructor, perché non lo usi?

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