关闭主窗口时,WPF 应用不会关闭

本文关键字:应用 WPF 窗口 | 更新日期: 2023-09-27 18:29:55

我习惯了Visual Studio中的WinForms编程,但我想尝试一下WPF。

我向项目添加了另一个窗口,称为 Window01。主窗口称为主窗口。在public MainWindow()构造函数之前,我声明 Window01:

Window01 w1;

现在,我在以下位置实例化此窗口:

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

我有一个显示窗口的按钮:w1.ShowDialog(); .

这里的"有趣"是,如果我启动应用程序(使用调试(并在几秒钟后退出它(我不在应用程序中执行任何操作(,Visual Studio 不会停止调试,就好像应用程序仍在运行一样。

如果我将行w1 = new Window01();移动到按钮单击方法,这意味着刚好在ShowDialog()上方,Visual Studio 运行正常 - 也就是说,当我退出应用程序时调试停止。

为什么会有这种奇怪的行为?

关闭主窗口时,WPF 应用不会关闭

在你的MainWindow.xaml.cs中,尝试这样做:

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);
    Application.Current.Shutdown();
}

根据此链接,您还可以在 XAML 中设置ShutdownMode

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>

仅当调用ApplicationShutdown 方法时,应用程序才会停止运行。关闭可以隐式或显式发生,如 ShutdownMode 属性的值所指定。

如果将ShutdownMode设置为 OnLastWindowClose ,则 Windows Presentation Foundation (WPF( 会在应用程序中的最后一个窗口关闭时隐式调用 Shutdown,即使将任何当前实例化的窗口设置为主窗口也是如此(请参阅 MainWindow(。

OnMainWindowClose ShutdownMode会导致 WPF 在主窗口关闭时隐式调用关闭,即使其他窗口当前处于打开状态也是如此。

某些应用程序的生存期可能不依赖于主窗口或最后一个窗口的关闭时间,或者可能根本不依赖于窗口。对于这些方案,您需要将 ShutdownMode 属性设置为 OnExplicitShutdown ,这需要显式Shutdown方法调用才能停止应用程序。否则,应用程序将继续在后台运行。

ShutdownMode可以从 XAML 以声明方式配置,也可以从代码以编程方式进行配置。

此属性只能从创建Application对象的线程中使用。


在您的情况下,应用程序不会关闭,因为您可能正在使用默认OnLastWindowClose

如果将ShutdownMode设置为 OnLastWindowClose ,则 WPF 会在应用程序中的最后一个窗口关闭时隐式调用 Shutdown,即使将任何当前实例化的窗口设置为主窗口也是如此(请参阅MainWindow(。

由于您正在打开一个新窗口,而不是关闭它,因此不会调用关机。

我很高兴

你得到了答案,但为了其他人,我也会回答你的问题以添加一些信息。


步骤 1

首先,如果您希望程序在主窗口关闭时退出,则需要指定,因为这不是此行为默认的 WinForms。

(WPF 中的默认值是最后一个窗口关闭时(

在代码中

入口点转到应用程序实例(在VS 2012的WPF程序中,默认嵌套在App.xaml中,因此请进入其中并导航到App.xaml.cs并创建构造函数(。

在构造函数中指定ApplicationShutdownModeShutdownModeOnLastWindowClose .

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

在 XAML 中

转到VS 2012默认创建的App.xaml文件(或自己创建(根是Application,里面指定你的ApplicationShutdownMode应该是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">

如果它有效,你就完成了;你可以停止阅读。


步骤 2

如果上述方法不起作用(我猜您是从头开始编写 WPF 应用程序的(,则应用程序可能不知道主窗口是主窗口。所以也指定了。

在代码中

像在步骤 1 中那样转到应用程序的构造函数,并指定该ApplicationMainWindow的价值就是您的Window

MainWindow = mainWindow;

在 XAML 中

按照在步骤 1 中执行的操作,转到 XAML Application,并指定该ApplicationMainWindow的价值就是您的Window

MainWindow = "mainWindow";

另类

我不认为这是最好的方法,只是因为 WPF 不希望你这样做(所以它有ApplicationShutdownMode(,但你可以只使用事件/覆盖事件方法(OnEventHappen(。

转到主窗口的代码隐藏文件并添加:

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        App.Current.Shutdown();
    }

因为 WPF 应用程序中的默认关闭模式是 OnLastWindowClose,这意味着应用程序在最后一个窗口关闭时停止。

实例化新的 Window 对象时,它会自动添加到应用程序中的窗口列表中。因此,问题在于您的应用程序在启动时正在创建两个窗口 - MainWindow 和尚未显示的 Window01 - 如果您只关闭 MainWindow,Window01 将使您的应用程序保持运行。

通常,您将使用将调用其 ShowDialog 的相同方法创建一个窗口对象,并且每次显示对话框时都会创建一个新的窗口对象。

我在搜索其他内容时偶然发现了这个问题,我很惊讶我看不到任何提到Window.Owner的建议答案。

    {
       var newWindow = new AdditionalWindow();
       newWindow.Owner = Window.GetWindow(this);
       // then later on show the window with Show() or ShowDialog()
    }

调用 Window.GetWindow(this) 在 MVVM 应用程序的视图中非常有用,当您在可视化树中很远而不知道您被实例化的位置时,可以通过提供任何FrameWork元素(例如 UserContolButtonPage(。 显然,如果您直接引用窗口,请使用该窗口,甚至Application.Current.MainWindow.

这是一个非常强大的关系,具有许多您可能一开始就没有意识到的有用好处(假设您没有专门编写单独的窗口来避免这些关系(。

如果我们将您的主窗口称为MainWindow,将第二个窗口称为AdditionalWindow那么......

  1. 尽量减少MainWindow也将最大限度地减少AdditionalWindow
  2. 恢复MainWindow也会恢复AdditionalWindow
  3. 关闭MainWindow将关闭AdditionalWindow,但关闭AdditionalWindow不会关闭MainWindow
  4. AdditioanlWindow永远不会在MainWindow下"迷失",即 如果您使用 Show() 显示它,AddditionalWindow总是以 z 顺序显示在 MainWindow 上方(非常有用!

但有一点需要注意,如果你有这种关系,那么不会调用AdditionalWindow上的Closing事件,所以你必须手动循环访问OwnedWindows集合。 例如 创建一种通过新接口或基类方法调用每个窗口的方法。

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

以上这些都不适合我,也许是因为我们的项目使用了 Prism。所以最终在 App.XAML 中使用它.cs

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

它看起来像我在创建第二个窗口以充当对话框时遇到的问题。 当第二个窗口打开然后关闭,然后关闭主窗口时,应用程序继续运行(在后台(。 我在我的 App.xaml 中添加(或确认(以下内容:

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

没有快乐。

因此,我最终进入了"MainWindow.xaml",并向Window添加了一个"Closed"属性,该属性转到如下所示的"MainWind_Closed"方法:

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

运行调试器,看起来唯一显示的窗口是我创建为对话框的窗口 - 换句话说,foreach 循环只找到一个窗口 - 对话框,而不是主窗口。

我有"这个。Close(("在关闭对话框的方法中运行,我有一个"dlgwin。Close((",在"dlgwin.ShowDialog((",这不起作用。 甚至没有"dlgwin = null"。

那么,如果没有这些额外的东西,为什么这个对话不会关闭呢? 哦,好吧。 这行得通。