web-dev-qa-db-fra.com

Disposition des contrôles utilisateur WPF

J'ai créé un contrôle utilisateur WPF personnalisé destiné à être utilisé par un tiers. Mon contrôle a un membre privé qui est jetable et je voudrais m'assurer que sa méthode de suppression sera toujours appelée une fois que la fenêtre/l'application contenant est fermée. Cependant, UserControl n'est pas jetable. J'ai essayé d'implémenter l'interface IDisposable et de m'abonner à l'événement Unloaded mais je ne me suis pas fait appeler à la fermeture de l'application hôte. Dans la mesure du possible, je ne veux pas que les consommateurs de mon contrôle se souviennent d'appeler une méthode Dispose spécifique.

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

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

     }
 }

La seule solution que j'ai trouvée jusqu'à présent consiste à s'abonner à l'événement ShutdownStarted de Dispatcher. Est-ce une approche raisonnable?

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

Article de blog intéressant ici:

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

Il mentionne s'abonner à Dispatcher.ShutdownStarted pour disposer de vos ressources.

56
Ray Booysen

Dispatcher.ShutdownStarted L'événement n'est déclenché qu'à la fin de l'application. Cela vaut la peine d'appeler la logique d'élimination au moment même où le contrôle devient inutilisable. En particulier, il libère des ressources lorsque le contrôle est utilisé plusieurs fois au cours de l'exécution de l'application. Donc, la solution de ioWint est préférable. Voici le 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

Vous devez être prudent en utilisant le destructeur. Ceci sera appelé sur le fil de discussion de GC Finalizer. Dans certains cas, les ressources que votre libération n'aime peut-être pas être publiées sur un thread différent de celui sur lequel elles ont été créées.

14
Ade Miller

J'utilise le comportement d'interactivité suivant pour fournir un événement de déchargement à WPF UserControls. Vous pouvez inclure le comportement dans le XAML UserControls. Ainsi, vous pouvez avoir la fonctionnalité sans placer la logique dans chaque UserControl.

Déclaration XAML:

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

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

Gestionnaire CodeBehind:

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

Code de comportement:

/// <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

Mon scénario est un peu différent, mais l’intention est la même. Je voudrais savoir quand la fenêtre parente qui héberge mon contrôle utilisateur se ferme/se ferme. (Nous implémentons un modèle MVP sur une application WPF PRISM).

Je viens de penser que dans l'événement Loaded du contrôle utilisateur, je peux connecter ma méthode ParentWindowClosing à l'événement Closing de la fenêtre Parent. De cette façon, mon Usercontrol peut être informé de la fermeture de la fenêtre Parent et agir en conséquence!

5
ioWint

Je pense que décharger s'appelle tout, mais il est difficile d'exister en 4.7. Mais si vous jouez avec les anciennes versions de .Net, essayez ceci dans votre méthode de chargement:

e.Handled = true;

Je ne pense pas que les anciennes versions seront déchargées tant que le chargement n’est pas traité. Je poste juste parce que je vois que d’autres posent encore cette question et que cela n’a pas été proposé comme solution. Je ne touche le Net que quelques fois par an et je l’ai rencontré quelques années auparavant. Mais, je me demande si c'est aussi simple que décharger ne pas être appelé jusqu'à ce que le chargement soit terminé. On dirait que cela fonctionne pour moi, mais encore une fois dans les nouveaux .Net, il semble toujours appeler unload même si le chargement n'est pas marqué comme étant géré.

0
Michael