Shutting down a WPF application from App.xaml.cs
Asked Answered
P

4

38

I am currently writing a WPF application which does command-line argument handling in App.xaml.cs (which is necessary because the Startup event seems to be the recommended way of getting at those arguments). Based on the arguments I want to exit the program at that point already which, as far as I know, should be done in WPF with Application.Current.Shutdown() or in this case (as I am in the current application object) probably also just this.Shutdown().

The only problem is that this doesn't seem to work right. I've stepped through with the debugger and code after the Shutdown() line still gets executed which leads to errors afterwards in the method, since I expected the application not to live that long. Also the main window (declared in the StartupUri attribute in XAML) still gets loaded.

I've checked the documentation of that method and found nothing in the remarks that tell me that I shouldn't use it during Application.Startup or Application at all.

So, what is the right way to exit the program at that point, i. e. the Startup event handler in an Application object?

Phooey answered 3/3, 2009 at 11:36 Comment(2)
What are the errors you're getting? Please update your question.Rounding
Click Here for a simple and working answerHerbartian
P
61

First remove the StartupUri property from App.xaml and then use the following:

    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);
        }
    }
Pryor answered 3/3, 2009 at 11:49 Comment(6)
Still doesn't work right :( Specifically I'm getting NullReferenceExceptions in the main window's constructor, which may be easily circumvented. But as far as I understand it shutting down the application should work without instantiating the window referenced by StartupUri.Phooey
I changed my answer to show you how you can avoid your main window to be created. It is important that you first remove the StartupUri from App.xaml.Pryor
Thanks. It works now. But I find it kinda unintuitive that the StartupUri is always loaded regardless whether the application should already have exited.Phooey
This doesn't work if you are trying to shut down from InitApplication(), as in my case. Even if StartupUri is null, which it already is in my case because I have no main window, this.Shutdown() has no effect.Overshoe
InitApplication() is executed before OnStartup(), so I have to set a boolean during InitApplication(), then call return, and check for the boolean in OnStartup() and then exit as above.Overshoe
When I do this, the program exits but the console window doesn't redraw the console. weird.Dissolution
C
9

If you remove the StartupUri from app.xaml for an application with a MainWindow you need to make sure you make the following call in your OnStartup method otherwise the application will not terminate when your MainWindow closes.

this.ShutdownMode = System.Windows.ShutdownMode.OnMainWindowClose;

@Frank Schwieterman, something along these lines may help you with your console window issue.

Coltun answered 15/2, 2013 at 18:14 Comment(1)
This page details the WPF startup and shutdown procedures very clearly... blackwasp.co.uk/WPFStartupShutdown.aspxLetha
A
1

I did this a little differently to avoid having to set the StartupUri and ShutdownMode properties. First edit the App.xaml file and replace StartupUri with 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>

Then add Application_Startup to the code along with OnExit:

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);
    }
Aldus answered 11/6, 2020 at 21:56 Comment(0)
K
0

Write in the 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;  
    }  
    ...
}
Katiekatina answered 18/1, 2023 at 11:35 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Classicize

© 2022 - 2024 — McMap. All rights reserved.