Die WPF-App wird beim Schließen des Hauptfensters nicht heruntergefahren

82

Ich bin an die WinForms-Programmierung in Visual Studio gewöhnt, wollte aber WPF ausprobieren.

Ich habe meinem Projekt ein weiteres Fenster namens Window01 hinzugefügt. Das Hauptfenster heißt MainWindow. Vor dem public MainWindow()Konstruktor deklariere ich Window01:

Window01 w1;

Jetzt instanziiere ich dieses Fenster in:

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

Ich habe eine Schaltfläche, in der das Fenster angezeigt wird : w1.ShowDialog();.

Das 'lustige' hier ist die Tatsache, dass Visual Studio das Debuggen nicht beendet, wenn ich die Anwendung starte (mit Debugging) und einige Sekunden später beende (ich mache nichts in der Anwendung), als ob die Anwendung es wäre funktioniert immer noch.

Wenn ich die Linie w1 = new Window01();zur Schaltfläche-Klick-Methode verschiebe, dh direkt darüberShowDialog() , verhält sich Visual Studio ordnungsgemäß. Das heißt, das Debuggen wird beendet, wenn ich die Anwendung beende.

Warum dieses seltsame Verhalten?

gosr
quelle

Antworten:

138

In Ihrem MainWindow.xaml.csversuchen dies zu tun:

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

    Application.Current.Shutdown();
}

Über diesen Link können Sie auch die ShutdownModein XAML festlegen :

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>

Anwendungen werden erst beendet, wenn die ShutdownMethode von Applicationaufgerufen wird. Das Herunterfahren kann implizit oder explizit erfolgen, wie durch den Wert der ShutdownModeEigenschaft angegeben.

Wenn Sie setzen ShutdownModeauf OnLastWindowClose, Windows Presentation Foundation (WPF) implizit ruft Shutdown , wenn das letzte Fenster in einer Anwendung schließt, auch wenn alle derzeit instanziiert Fenster als Hauptfenster gesetzt werden (siehe Hauptfenster).

A ShutdownModevon OnMainWindowClosebewirkt, dass WPF beim Schließen des MainWindow implizit Shutdown aufruft, selbst wenn derzeit andere Fenster geöffnet sind.

Die Lebensdauer einiger Anwendungen hängt möglicherweise nicht davon ab, wann das Hauptfenster oder das letzte Fenster geschlossen wird, oder hängt überhaupt nicht von Fenstern ab. Für diese Szenarien müssen Sie die ShutdownModeEigenschaft auf festlegen OnExplicitShutdown, was einen expliziten ShutdownMethodenaufruf erfordert , um die Anwendung zu stoppen. Andernfalls wird die Anwendung im Hintergrund weiter ausgeführt.

ShutdownMode kann deklarativ aus XAML oder programmgesteuert aus Code konfiguriert werden.

Diese Eigenschaft ist nur in dem Thread verfügbar, der das ApplicationObjekt erstellt hat.


In Ihrem Fall wird die App nicht geschlossen, da Sie wahrscheinlich die Standardeinstellung verwenden OnLastWindowClose:

Wenn Sie ShutdownModediese OnLastWindowCloseOption festlegen , ruft WPF implizit Shutdown auf, wenn das letzte Fenster in einer Anwendung geschlossen wird, auch wenn derzeit instanziierte Fenster als Hauptfenster festgelegt sind (siehe MainWindow).

Da Sie ein neues Fenster öffnen und nicht schließen, wird das Herunterfahren nicht aufgerufen.

Bob Horn
quelle
1
Es ist wichtig zu beachten, dass die Überschreibungsfunktion am besten ist, wenn Sie andere Threads instanziiert haben, um bestimmte Aufgaben auszuführen. Stoppen Sie die Threads in der OnClosed-Funktion, bevor Sie das Schließen beenden. Andernfalls bleiben die Threads am Leben und die App wird nie wirklich beendet.
weezma2004
Ich bin mir nicht sicher, ob es eine gute Idee ist, eine Anwendung herunterzufahren, nur weil MainWindow geschlossen ist. Es ist auch möglich, dass dieser Hintergrundprozess versucht, etwas in der Datenbank zu speichern, in Protokolle zu schreiben, Dinge zwischenzuspeichern, Geräte zu trennen usw. An diesem Punkt würde ich das Problem finden, das die Anwendung blockiert, schließen und es beheben. Organisieren Sie immer Ihren Anwendungslebenszyklus. Application.Current.Shutdown()wird die Anwendung sofort herunterfahren, wie wenn der Vorgang in der Taskleiste abgeschlossen ist. Das ist wie jemanden zu erschießen, bevor er sein letztes Wort sagt :) .. würde ich nicht empfehlen.
Vural
35

Ich bin froh, dass Sie Ihre Antwort erhalten haben, aber für andere werde ich auch Ihre Frage beantworten, um einige Informationen hinzuzufügen.


Schritt 1

Wenn Sie möchten, dass Ihr Programm beim Schließen des Hauptfensters beendet wird, müssen Sie zunächst angeben, dass dies nicht WinForms ist, bei dem dieses Verhalten standardmäßig verwendet wird.

(Die Standardeinstellung in WPF ist, wenn das letzte Fenster geschlossen wird.)

In Code

Gehen Sie zu Ihrer Anwendungsinstanz in Ihrem Einstiegspunkt (in VS 2012 WPF - Programm ist die Standard - verschachtelte innen App.xaml, also gehen Sie innerhalb es und navigieren Sie zu App.xaml.csund einen Konstruktor erstellen).

Im Konstruktor angeben , dass Ihre Application‚s ShutdownModesein sollte ShutdownMode. OnLastWindowClose.

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

In XAML

Gehen Sie zu Ihrer App.xamlDatei , dass VS 2012 standardmäßig erstellt (oder erstellen Sie es selbst) Die Wurzel ist ein Application, geben Sie im Inneren , dass Ihr Application‚s ShutdownModesein sollte 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">

Wenn es funktioniert, sind Sie fertig; Sie können aufhören zu lesen.


Schritt 2

Wenn das oben genannte nicht funktioniert hat (ich denke, Sie haben die WPF-Anwendung von Grund auf neu geschrieben), ist das Hauptfenster der Anwendung wahrscheinlich nicht als Hauptfenster bekannt. Geben Sie dies auch an.

In Code

Gehen Sie wie in Schritt 1 zum Konstruktor der Anwendung und geben Sie dies an Application. MainWindowDer Wert ist Ihr Window:

MainWindow = mainWindow;

In XAML

Gehen ApplicationSie wie in Schritt 1 zur XAML und geben Sie dies an Application. MainWindowDer Wert ist Ihr Window:

MainWindow = "mainWindow";

Alternative

Ich glaube nicht , das ist der beste Ansatz ist, nur weil WPF nicht , dass Sie dies tun will (so hat es Application‚s ShutdownMode), aber man kann nur ein Ereignis / außer Kraft eine Event - Methode (OnEventHappened) verwenden.

Gehen Sie zur CodeBehind-Datei des MainWindow und fügen Sie Folgendes hinzu:

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

        App.Current.Shutdown();
    }
MasterMastic
quelle
3
Ihre Antwort ist besser als die, die markiert ist.
Seekeer
Ich mache es in der Regel so aus : Set MainWindowauf die Instanz des Hauptfensters, setzen ShutdownModeauf ShutdownMode.OnMainWindowClose, Anruf MainWindow.Show()in Rückruf StartupFall App. Dies ist die minimalste Lösung, die ich mir ausgedacht habe und die zumindest in .NET Core 3 mit WPF wie erwartet funktioniert.
TorbenJ
11

Da der Standardmodus zum Herunterfahren in einer WPF-Anwendung OnLastWindowClose ist, wird die Anwendung gestoppt, wenn das letzte Fenster geschlossen wird.

Wenn Sie ein neues Fensterobjekt instanziieren, wird es automatisch zur Liste der Fenster in der Anwendung hinzugefügt . Das Problem war also, dass Ihre Anwendung beim Start zwei Fenster erstellte - das MainWindow und das noch nicht angezeigte Window01 - und wenn Sie nur das MainWindow geschlossen haben, würde das Window01 Ihre Anwendung weiter ausführen.

Normalerweise erstellen Sie ein Fensterobjekt mit derselben Methode, mit der der ShowDialog aufgerufen wird, und Sie erstellen jedes Mal ein neues Fensterobjekt, wenn der Dialog angezeigt wird.

Joe Daley
quelle
2

Ich bin bei der Suche nach etwas anderem auf diese Frage gestoßen und war überrascht, dass ich keine der vorgeschlagenen Antworten sehen konnte, über die gesprochen wurde Window.Owner.

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

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

Ein Aufruf Window.GetWindow(this)ist sehr nützlich im Hinblick auf einer MVVM - Anwendung , wenn Sie weit unten auf der visuellen Struktur nicht zu wissen, wo man instanziiert wurde, kann es durch die Übermittlung von heißem FrameWorkElemente ( zum Beispiel UserContol, Button, Page). Wenn Sie einen direkten Verweis auf das Fenster haben, verwenden Sie diesen oder sogar diesen Application.Current.MainWindow.

Dies ist eine ziemlich leistungsstarke Beziehung, die eine Reihe nützlicher Vorteile bietet, die Sie möglicherweise zunächst nicht realisieren (vorausgesetzt, Sie haben keine separaten Fenster speziell codiert, um diese Beziehungen zu vermeiden).

Wenn wir Ihr Hauptfenster MainWindowund das zweite Fenster wie AdditionalWindowdamals nennen ...

  1. Das Minimieren des MainWindowWillens wird ebenfalls minimiertAdditionalWindow
  2. Das Wiederherstellen MainWindowwird ebenfalls wiederhergestelltAdditionalWindow
  3. Das Schließen MainWindowwird geschlossen AdditionalWindow, das Schließen AdditionalWindowjedoch nichtMainWindow
  4. AdditioanlWindowwird nie "verloren" gehen unter MainWindow, dh AddditionalWindowimmer oben MainWindowin der Z-Reihenfolge Show()angezeigt , wenn Sie es früher angezeigt haben (sehr nützlich!)

Wenn Sie diese Beziehung haben, wird das ClosingEreignis auf dem AdditionalWindownicht aufgerufen, sodass Sie die OwnedWindowsSammlung manuell durchlaufen müssen . Beispiel: Erstellen Sie eine Möglichkeit, jedes Fenster über eine neue Schnittstelle oder eine Basisklassenmethode aufzurufen.

    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();
        }        
    }
Rhys
quelle
1

Keiner der oben genannten Punkte hat für mich funktioniert, vielleicht weil unser Projekt Prism verwendet. So endete dies in der App.XAML.cs

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);
        Process.GetCurrentProcess().Kill();
    }
Sadis
quelle
0

Es sieht aus wie etwas, auf das ich gestoßen bin, als ich ein zweites Fenster als Dialogfeld erstellt habe. Wenn das zweite Fenster geöffnet und dann geschlossen und dann das Hauptfenster geschlossen wurde, lief die App weiter (im Hintergrund). Ich habe Folgendes in meiner App.xaml hinzugefügt (oder bestätigt):

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

Keine Freude.

Also ging ich schließlich in meine "MainWindow.xaml" und fügte dem Fenster eine "Closed" -Eigenschaft hinzu, die zu einer "MainWind_Closed" -Methode ging, die wie folgt aussieht:

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

Wenn Sie den Debugger durchlaufen, wird anscheinend nur das Fenster angezeigt, das ich als Dialogfeld erstellt habe. Mit anderen Worten, die foreach-Schleife findet nur ein Fenster - das Dialogfeld, nicht das Hauptfenster.

Ich hatte "this.Close ()" in der Methode ausgeführt, die den Dialog schloss, und ich hatte ein "dlgwin.Close ()", das nach dem "dlgwin.ShowDialog ()" kam, und das funktionierte nicht. Nicht einmal ein "dlgwin = null".

Warum sollte dieser Dialog ohne dieses zusätzliche Material nicht geschlossen werden? Naja. Das funktioniert.

Lowell
quelle