【问题标题】:WPF App Doesn't Shut Down When Closing Main Window关闭主窗口时 WPF 应用程序不会关闭
【发布时间】:2012-04-17 00:56:55
【问题描述】:

我习惯在 Visual Studio 中进行 WinForms 编程,但我想尝试一下 WPF。

我在我的项目中添加了另一个窗口,称为 Window01。主窗口称为 MainWindow。在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 的行为正常 - 也就是说,当我退出应用程序时,调试停止。

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

【问题讨论】:

    标签: c# wpf visual-studio-2010 window


    【解决方案1】:

    在您的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 在 MainWindow 关闭时隐式调用 Shutdown,即使其他窗口当前打开也是如此。

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

    ShutdownMode 可以通过 XAML 以声明方式配置,也可以通过代码以编程方式配置。

    此属性仅在创建 Application 对象的线程中可用。


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

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

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

    【讨论】:

    • 重要的是要注意,如果您已实例化任何其他线程来执行某些任务,则覆盖功能是最好的。在关闭完成之前停止 OnClosed 函数中的线程。否则线程保持活跃,应用程序永远不会真正退出。
    • 我不确定关闭应用程序是否是个好主意,只是因为 MainWindow 已关闭。也有可能,后台进程正在尝试做一些事情,比如保存到数据库、写入日志、缓存东西、断开设备等......此时,我会发现阻止应用程序关闭并修复它的问题。始终组织您的应用程序生命周期。Application.Current.Shutdown() 将立即关闭应用程序,就像在任务栏上完成进程一样。这就像在他说最后一句话之前射击某人:)..我不推荐。
    【解决方案2】:

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

    当您实例化一个新的 Window 对象时,它会自动添加到应用程序中的list of windows。所以,问题在于您的应用程序在启动时创建了两个窗口 - MainWindow 和尚未显示的 Window01 - 如果您只关闭 MainWindow,Window01 将使您的应用程序继续运行。

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

    【讨论】:

      【解决方案3】:

      很高兴您得到了答案,但为了其他人,我会回答您的问题并添加一些信息。


      步骤 1

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

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

      在代码中

      在您的入口点中转到您的应用程序实例(在 VS 2012 的 WPF 程序中,默认嵌套在 App.xaml 内,所以转到 inside 它并导航到 App.xaml.cs 并创建一个构造函数)。

      在构造函数中指定您的ApplicationShutdownMode 应为ShutdownMode.OnLastWindowClose

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

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


      第二步

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

      在代码中

      像第 1 步一样转到应用程序的构造函数,并指定 Application.MainWindow 的值是您的 Window

      MainWindow = mainWindow;
      

      在 XAML 中

      按照您在步骤 1 中所做的那样转到 Application XAML,并指定 Application.MainWindow 的值是您的 Window

      MainWindow = "mainWindow";
      

      另类

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

      转到 MainWindow 的代码隐藏文件并添加:

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

      【讨论】:

      • 你的答案比被标记的要好。
      • 我通常这样做:将MainWindow设置为主窗口的实例,将ShutdownMode设置为ShutdownMode.OnMainWindowClose,在AppStartup事件的回调中调用MainWindow.Show()。这是我想出的最小的解决方案,至少在带有 WPF 的 .NET Core 3 中可以按预期工作。
      【解决方案4】:

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

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

      不开心。

      所以,我终于进入了我的“MainWindow.xaml”并向窗口添加了一个“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 循环只找到一个窗口——对话框,而不是主窗口。

      我在关闭对话框的方法中运行了“this.Close()”,并且在“dlgwin.ShowDialog()”之后出现了一个“dlgwin.Close()”,但这不起作用.甚至没有“dlgwin = null”。

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

      【讨论】:

        【解决方案5】:

        我在搜索其他内容时偶然发现了这个问题,我很惊讶我看不到任何提及 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();
                }        
            }
        

        【讨论】:

          【解决方案6】:

          以上方法都不适合我,可能是因为我们的项目使用了 Prism。 所以最终在 App.XAML.cs 中使用了这个

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多