web-dev-qa-db-fra.com

L'application WPF ne s'arrête pas lors de la fermeture de la fenêtre principale

Je suis habitué à la programmation WinForm dans Visual Studio, mais je voulais essayer WPF.

J'ai ajouté une autre fenêtre à mon projet, appelée Window01. La fenêtre principale s'appelle MainWindow. Avant le constructeur public MainWindow() je déclare Window01:

Window01 w1;

Maintenant j'instancie cette fenêtre en:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    w1 = new Window01();            
}

J'ai un bouton où la fenêtre est affichée: w1.ShowDialog();.

La chose «amusante» ici est le fait que si je lance l'application (avec le débogage) et que je la quitte quelques secondes après (je ne fais rien dans l'application), Visual Studio n'arrête pas le débogage comme si l'application était en cours. cours toujours.

Si je déplace la ligne w1 = new Window01(); vers la méthode de clic, ce qui signifie juste au-dessus de ShowDialog(), Visual Studio se comporte correctement. En d'autres termes, le débogage s'arrête lorsque je quitte l'application.

Pourquoi ce comportement étrange?

64
eightx2

Dans votre MainWindow.xaml.cs, essayez ceci:

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);

    Application.Current.Shutdown();
}

Par ce lien, vous pouvez également définir la ShutdownMode en XAML:

http://msdn.Microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx

<Application
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml"
    ShutdownMode="OnExplicitShutdown"
    >
</Application>

Les applications s’arrêtent uniquement lorsque la méthode Shutdown de Application est appelée. L'arrêt peut se produire de manière implicite ou explicite, comme spécifié par la valeur de la propriété ShutdownMode.

Si vous définissez ShutdownMode sur OnLastWindowClose, Windows Presentation Foundation (WPF) appelle implicitement Shutdown lors de la fermeture de la dernière fenêtre d'une application, même si l'une des fenêtres instanciées en cours est définie comme fenêtre principale (voir MainWindow).

Une ShutdownMode sur OnMainWindowClose fait que WPF appelle implicitement Shutdown à la fermeture de MainWindow, même si d'autres fenêtres sont actuellement ouvertes.

La durée de vie de certaines applications peut ne pas dépendre du moment où la fenêtre principale ou de la dernière fenêtre est fermée, ou peut ne pas dépendre du tout de fenêtres. Pour ces scénarios, vous devez définir la propriété ShutdownMode sur OnExplicitShutdown, ce qui nécessite un appel explicite à la méthode Shutdown pour arrêter l'application. Sinon, l'application continue de s'exécuter en arrière-plan.

ShutdownMode peut être configuré de manière déclarative à partir de XAML ou par programme à partir de code.

Cette propriété est disponible uniquement à partir du thread qui a créé l'objet Application.


Dans votre cas, l'application ne ferme pas car vous utilisez probablement la valeur par défaut OnLastWindowClose:

Si vous définissez ShutdownMode sur OnLastWindowClose, WPF appelle implicitement Shutdown lorsque la dernière fenêtre d'une application se ferme, même si l'une des fenêtres instanciées actuellement est définie comme fenêtre principale (voir MainWindow).

Puisque vous ouvrez une nouvelle fenêtre et que vous ne la fermez pas, l’arrêt n’est pas appelé.

113
Bob Horn

Je suis content que vous ayez eu votre réponse, mais pour le plaisir des autres, je vais répondre à votre question et ajouter quelques informations.


Étape 1

Tout d'abord, si vous souhaitez que votre programme se ferme à la fermeture de la fenêtre principale, vous devez spécifier car il ne s'agit pas de WinForms où ce comportement est défini par défaut.

(La valeur par défaut dans WPF est celle de la fermeture de la dernière fenêtre)}

Dans du code

Accédez à votre instance d'application dans votre point d'entrée (dans le programme WPF de VS 2012, la valeur par défaut est imbriquée dans App.xaml, donc accédez à inside et accédez à App.xaml.cs et créer un constructeur).

Dans le constructeur, spécifiez que votre Application 's ShutdownMode doit être ShutdownMode .OnLastWindowClose.

    public App()
    {
        ShutdownMode = ShutdownMode.OnLastWindowClose;
    }

En XAML

Allez dans votre fichier App.xaml créé par défaut par VS 2012 (ou créez-le vous-même) La racine est une Application, spécifiez à l'intérieur que votre Application 's ShutdownMode doit être ShutdownMode . OnLastWindowClose.

<Application x:Class="WpfApplication27.App"
         xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
         StartupUri="MainWindow.xaml"
         ShutdownMode="OnMainWindowClose">

Si cela fonctionne, vous avez terminé. vous pouvez arrêter de lire.


Étape 2

Si ce qui précède n'a pas fonctionné (je suppose que vous avez écrit l'application WPF à partir de rien), la fenêtre principale n'est probablement pas connue de l'application sous le nom de fenêtre principale . Spécifiez-le également.

Dans du code

Accédez au constructeur de l'application comme à l'étape 1 et spécifiez que la valeur de Application . MainWindow / est votre Window :

MainWindow = mainWindow;

En XAML

Accédez à la variable XAML Application comme à l'étape 1 et indiquez que la valeur de Application . MainWindow est votre Window :

MainWindow = "mainWindow";

Alternative

Je ne pense pas que ce soit la meilleure approche, simplement parce que WPF ne veut pas que vous fassiez cela (donc elle a Application 's ShutdownMode ), mais vous pouvez simplement utiliser un événement/méthode d'événement (OnEventHappened).

Allez dans le fichier code-behind de MainWindow et ajoutez:

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);

        App.Current.Shutdown();
    }
25
MasterMastic

Comme le mode shutdown par défaut dans une application WPF est OnLastWindowClose, ce qui signifie que l'application s'arrête à la fermeture de la dernière fenêtre.

Lorsque vous instanciez un nouvel objet Window, il est automatiquement ajouté à la liste de windows de l'application. Le problème était donc que votre application créait deux fenêtres à son démarrage - MainWindow et Window01 non encore affichée - et si vous ne fermiez que MainWindow, Window01 maintiendrait votre application en marche.

Normalement, vous allez créer un objet window avec la même méthode que son ShowDialog et créer un nouvel objet window à chaque fois que la boîte de dialogue est affichée.

11
Joe Daley

Je suis tombé sur cette question en cherchant autre chose et j'ai été surpris de ne voir aucune des réponses proposées mentionner Window.Owner.

    {
       var newWindow = new AdditionalWindow();
       newWindow.Owner = Window.GetWindow(this);

       // then later on show the window with Show() or ShowDialog()
    }

Un appel à Window.GetWindow(this) est très utile dans la vue d'une application MVVM lorsque vous êtes loin de l'arborescence visuelle sans savoir où vous avez été instancié. Vous pouvez l'appeler en fournissant n'importe quel élément FrameWork (par exemple, UserContol, Button, Page). Évidemment, si vous avez une référence directe à la fenêtre, utilisez-la ou même Application.Current.MainWindow.

Il s'agit d'une relation assez puissante qui présente un certain nombre d'avantages utiles dont vous pourriez ne pas vous rendre compte au début (en supposant que vous n'ayez pas codé spécifiquement des fenêtres séparées pour éviter ces relations).

Si nous appelons votre fenêtre principale MainWindow et la deuxième fenêtre comme AdditionalWindow, alors ...

  1. Minimiser la MainWindow réduira également AdditionalWindow 
  2. Restaurer MainWindow restaurera également AdditionalWindow
  3. La fermeture MainWindow ferme AdditionalWindow, mais la fermeture AdditionalWindow ne ferme pas MainWindow
  4. AdditioanlWindow ne sera jamais "perdu" sous MainWindow, c'est-à-dire que AddditionalWindow s'affiche toujours au-dessus de MainWindow dans l'ordre z si vous avez utilisé Show() pour l'afficher (très utile!)

Une chose à noter cependant, si vous avez cette relation, l’événement Closing de la AdditionalWindow n’est pas appelé, vous devez donc effectuer une itération manuelle sur la collection OwnedWindows. par exemple. Créez un moyen d'appeler chaque fenêtre via une nouvelle méthode d'interface ou de classe de base.

    private void MainWindow_OnClosing(object sender, CancelEventArgs e)
    {
        foreach (var window in OwnedWindows)
        {
            var win = window as ICanCancelClosing;  // a new interface you have to create
            e.Cancel |= win.DoYouWantToCancelClosing();
        }        
    }
0
Rhys

Cela ressemble à quelque chose que j'ai rencontré lorsque j'ai créé une deuxième fenêtre pour agir comme une boîte de dialogue. Lorsque la deuxième fenêtre a été ouverte, puis fermée, puis la fenêtre principale a été fermée, l'application a continué à s'exécuter (en arrière-plan). J'ai ajouté (ou confirmé) ce qui suit dans mon App.xaml:

<Application x:Class="XXXXXXX.App"
             ...  
             StartupUri="MainWindow.xaml"
             ShutdownMode="OnMainWindowClose">
    <Application.MainWindow >
        <NavigationWindow Source="MainWindow.xaml" Visibility="Visible" />
    </Application.MainWindow>

Pas de joie.

Alors, je suis finalement allé dans mon "MainWindow.xaml" et j'ai ajouté une propriété "Fermé" à la fenêtre qui est passé à une méthode "MainWind_Closed" qui ressemble à ce qui suit:

 private void MainWind_Closed(object sender, EventArgs e)
        {
            foreach ( Window w in App.Current.Windows )
            {
                if (w.DataContext != this)
                    w.Close();
            }
        }

En parcourant le débogueur, il semble que la seule fenêtre qui s'affiche soit celle que j'ai créée en tant que boîte de dialogue. En d'autres termes, la boucle foreach ne trouve qu'une seule fenêtre, la boîte de dialogue et non la fenêtre principale.

J'avais "this.Close ()" en cours d'exécution dans la méthode qui a fermé la boîte de dialogue et un "dlgwin.Close ()" après le "dlgwin.ShowDialog ()" et cela n'a pas fonctionné. Pas même un "dlgwin = null".

Alors, pourquoi ce dialogue ne se terminerait-il pas sans ce matériel supplémentaire? Tant pis. Cela marche.

0
Lowell