#50 – Application-Scoped Properties

The Application class includes a property named Properties that is an IDictionary of properties, stored as keyword/value pairs.  You can use this dictionary to store any properties that should have application scope.

Property values can be read from or written to the Properties dictionary from any thread, in a thread-safe manner.

 private void Application_Startup(object sender, StartupEventArgs e)
 {
     this.Properties.Add("Debug", false);
     this.Properties.Add("Logger", null);

     // Set properties based on command line parameters
     foreach (string a in e.Args)
     {
         if (a.ToLower() == "/debug")
             this.Properties["Debug"] = true;
         else if (a.ToLower() == "/logging")
             this.Properties["Logger"] = new MyAppLogger("Logfile.txt");
     }
 }

Each entry in the dictionary is of type System.Collections.DictionaryEntry, so it has a Key property (type object) and a Value property (type object).  This means that you can use objects of any type as either keys or values.  You’ll most often use strings as keys and various objects as values.

#49 – Unhandled Exceptions

When an exception gets thrown in a WPF application and not handled anywhere in the code, an unhandled exception occurs and the application is forced to exit.  This will result in a window similar to the following:

When this happens, the application exits suddenly, the user has no chance to save any uncompleted work and the user gets no additional information.  In short, the application crashes.

You can handle exceptions that would otherwise be unhandled by handling the Application.DispatcherUnhandledException event.  In the example below, we display a better error message and set the Handled property, to avoid shutting down the application.

 private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
 {
     string friendlyMsg = string.Format("SO sorry that something went wrong.  The error was: [{0}]", e.Exception.Message);
     string caption = "Error";
     MessageBox.Show(friendlyMsg, caption, MessageBoxButton.OK, MessageBoxImage.Error);

     // Signal that we handled things--prevents Application from exiting
     e.Handled = true;
 }

This results in a better error:

#48 – Handling an Application’s Exit Event

You can add code to the Application.Exit event handler to perform miscellaneous tasks that need doing at application shutdown/exit.

<Application x:Class="WpfApplication4.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             Exit="Application_Exit">
</Application>

private void Application_Exit(object sender, ExitEventArgs e)
{
    // Perform tasks at application exit
}

The Exit event is fired when the application is shutting down or the Windows session is ending.  It is fired after the SessionEnding event.  You cannot cancel the Exit event.

#47 – Detecting When the Windows Session is Ending

In WPF, you can detect when a user is ending their Windows session by handling the Application.SessionEnding event.  This occurs when the user is logging out of Windows or shutting down the machine.

In your event handler, you have the ability to cancel the termination of the Windows session by setting SessionEndingCancelEventArgs.Cancel to true.

 private void Application_SessionEnding(object sender, SessionEndingCancelEventArgs e)
 {
    MessageBoxResult res = MessageBox.Show("Exiting Windows will terminate this app.  Are you sure?", "End Session", MessageBoxButton.YesNo);
    if (res == MessageBoxResult.No)
    {
        e.Cancel = true;
    }
 }

Note that this event fires when Windows is exiting, but not when the application is closed in the normal manner.

On Windows 7, if your application cancels the SessionEnding event for a shutdown, Windows will inform the user that your application is preventing Windows from shutting down:

Update (Jan-2011): It’s probably cleaner to just override the OnSessionEnding method in your Application-derived class, rather than adding an event handler.

#46 – Processing Command Line Arguments in a WPF Application

You can process command line arguments passed in to a WPF application by reading the arguments in the event handler for the application’s Startup event.

Command line arguments can be found in StartupEventArgs.ArgsArgs is an array of string objects containing the arguments passed in on the command line.

private void Application_Startup(object sender, StartupEventArgs e)
{
    foreach (string s in e.Args)
    {
        MessageBox.Show(string.Format("Arg: {0}", s));
    }
}


You could also just override the OnStartup method, rather than adding a handler for the Startup event.

#45 – Two Ways to Create WPF Controls

When working with WPF, you can always create controls in one of two basic ways:

  • Create the control programmatically, from within your code (e.g. C#)
  • Create the control declaratively, in XAML

As an example, here are two different ways to create a main window for a WPF application.

To create a main window in code, you would add code the the Application object’s event handler for the Startup event.  You would typically create the window object and then call its Show method.

private void Application_Startup(object sender, StartupEventArgs e)
{
    MainWindow win = new MainWindow();
    win.Show();
}


More typically, you’d specify the application’s main window in XAML by specifying a value for the application’s StartupUri attribute.  For the default project created by the New Project wizard, you’d do this in App.xaml:

<Application x:Class="WpfApplication.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml">
    <Application.Resources>
    </Application.Resources>
</Application>

#44 – Application is a Singleton

The System.Application class is a singleton, which means that you can create at most one instance of Application (within a single AppDomain).  If you try creating a second instance of Application, you’ll get an InvalidOperationException.

You can access the current Application object through the static property Application.Current.  (Or use property of the derived class, e.g. App.Current).