从App.xaml.cs关闭一个WPF应用程序

38
我正在编写一个 WPF 应用程序,需要在 App.xaml.cs 中处理命令行参数(这是必要的,因为启动事件似乎是访问这些参数的建议方式)。根据参数,我想在那个时候退出程序,这应该在 WPF 中使用 Application.Current.Shutdown() 完成,或者在当前应用程序对象中也可以使用 this.Shutdown()
唯一的问题是这似乎没有正常工作。我通过调试器进行了跟踪,在 Shutdown() 行之后的代码仍然被执行,这导致方法后面出现错误,因为我期望应用程序不会再继续运行。此外,主窗口(在 XAML 中声明的 StartupUri 属性)仍然会被加载。
我已经检查了该方法的文档,并没有在备注中找到任何提示,告诉我不应该在 Application.StartupApplication 中使用它。
所以,在一个 Application 对象的 Startup 事件处理程序中退出程序的正确方法是什么?

1
你遇到了哪些错误?请更新你的问题。 - Kent Boogaart
点击这里获取一个简单且有效的答案。 - benshabatnoam
4个回答

60

首先从App.xaml中移除StartupUri属性,然后使用以下内容:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        bool doShutDown = ...;

        if (doShutDown)
        {
            Shutdown(1);
            return;
        }
        else
        {
            this.StartupUri = new Uri("Window1.xaml", UriKind.Relative);
        }
    }

仍然不能正常工作 :( 具体来说,我在主窗口的构造函数中遇到了NullReferenceExceptions,这可能很容易地被规避。但据我所知,关闭应用程序时不需要实例化由StartupUri引用的窗口。 - Joey
4
我修改了答案以向您展示如何避免创建主窗口。重要的是,您首先需要从App.xaml中删除StartupUri。 - Jakob Christensen
1
谢谢。现在它可以工作了。但是我发现启动URI始终会被加载,无论应用程序是否已经退出,这有点不直观。 - Joey
如果您正在尝试从InitApplication()关闭应用程序,则此方法不起作用,就像我的情况一样。即使StartupUri为空,在我的情况下已经是这样,因为我没有主窗口,this.Shutdown()也没有效果。 - noobish
在执行 OnStartup() 之前会先执行 InitApplication(),因此我必须在 InitApplication() 中设置一个布尔值,然后调用 return,并在 OnStartup() 中检查该布尔值,然后像上面一样退出。 - noobish
当我这样做时,程序退出了,但控制台窗口没有重新绘制。很奇怪。 - Frank Schwieterman

9
如果在一个具有MainWindow的应用程序的app.xaml中删除StartupUri,您需要确保在OnStartup方法中进行以下调用,否则当您的MainWindow关闭时,应用程序将无法终止。
this.ShutdownMode = System.Windows.ShutdownMode.OnMainWindowClose;

@Frank Schwieterman,以下内容可能有助于解决您的控制台窗口问题。


1
本页面非常清晰地详细介绍了WPF的启动和关闭过程... http://www.blackwasp.co.uk/WPFStartupShutdown.aspx - Steve Hibbert

1
我稍微以不同的方式处理,避免设置 StartupUriShutdownMode 属性。首先编辑 App.xaml 文件,并将 StartupUri 替换为 Startup:
<Application x:Class="Menu.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:Menu"
         Startup="Application_Startup">
    <Application.Resources>
    </Application.Resources>
</Application>

然后与OnExit一起将Application_Startup添加到代码中:

public partial class App : Application
{
    private volatile static Mutex s_mutex;

    private void Application_Startup(object sender, StartupEventArgs e)
    {
        s_mutex = new Mutex(true, @"Global\MenuMutex", out bool grantedOwnership);

        if (!grantedOwnership)
        {
            MessageBox.Show($"Another instance is already running!", "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            Current.Shutdown();
        }
        else
            new MainWindow().Show();
    }

    protected override void OnExit(ExitEventArgs e)
    {
        s_mutex?.ReleaseMutex();
        s_mutex?.Dispose();
        s_mutex = null;
        base.OnExit(e);
    }

0
在 Application_Startup 中编写:
private void Application_Startup(object sender, StartupEventArgs e)  
{  
    ...
    if (!condition)  
    {  
        e.GetType()  
          .GetProperty("PerformDefaultAction", BindingFlags.Instance | BindingFlags.NonPublic)  
          .SetValue(e, false);  
        Shutdown();  
        return;  
    }  
    ...
}

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接