#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.

Advertisement

#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).

#43 – What Happens in WPF Main() Function

When creating a new WPF standalone application using the New Project wizard in Visual Studio 2013, Visual Studio automatically creates a class that derives from System.Windows.Application, as well as a static Main() function that will be the first function called when the application is started.

Here’s how the main application object is defined:

 public partial class App : Application

During the Main method, the application is started up by:

  • Creating a new instance of the Application object
  • Calling Application.InitializeComponent to constitute the application from App.xaml
  • Calling Application.Run to start the application
public static void Main()
{
    WpfApplication.App app = new WpfApplication.App();
    app.InitializeComponent();
    app.Run();
}

#42 – WPF Application Entry Point

For a WPF standalone application that is generated in Visual Studio 2010 using the New Project wizard, the entry point for the application is the Main function, defined in App.g.cs (generated code).  In the default project, this is the public static void App.Main method.

In general, a .NET application will use as its entry point (first function called) any method named Main that has public/static access modifiers–no matter what class Main is located in.

If your application has more than one class with a public static Main method, you’ll need to specify the entry point in the project properties dialog.  In the Startup object dropdown, select the class that contains the Main method that should be called on startup.

#41 – Window Events at Startup and Shutdown

At application startup, the Window events that are fired (in order) for the main window are:

  • Initialized – Main window is being created
  • IsVisibleChanged IsVisible property set to true
  • SizeChanged – Size property set to size of window
  • LayoutUpdated – Window layout changes
  • SourceInitialized – Window is attached to Win32 window handle
  • Activated – Window becomes foreground window
  • PreviewGotKeyboardFocus – Window getting focus
  • IsKeyboardFocusWithinChanged IsKeyboardFocusWithin property set to true
  • IsKeyboardFocusedChanged IsKeyboardFocused property set to true
  • GotKeyboardFocus – Window now has keyboard focus
  • LayoutUpdated – Window layout changes
  • Loaded – Window is now laid out, fully rendered
  • ContentRendered – All window content has been rendered

At application shutdown, the Window events fired (in order) are:

  • Closing – Window is going to close
  • IsVisibleChanged IsVisible property set to false
  • Deactivated – Window becomes background window
  • IsKeyboardFocusWithinChanged IsKeyboardFocusWithin property set to false
  • IsKeyboardFocusedChanged IsKeyboardFocused property set to false
  • LostKeyboardFocus – Window no longer has keyboard focus
  • Closed – Window is closing