1. What is the Application Class:
When we run any WPF application, it is
represented by an instance of the System.Windows.Application class. The job of this
class is to track all open windows in our application, decide when our
application will shut down and fires application events that we handle to
perform initialization and other work. So every WPF application uses the Application
class which is why it's important to understand it.
The System.Windows.Application class plays the same role in a WPF application as
the System.Windows.Forms.Application class plays in a Windows Forms application.
2. Application life cycle:
A WPF application undergoes a straight forward
life cycle. When we start our application, the application objects are created,
and as our application runs, lots of events are fired. Finally, when the
application object is released, our application ends.
So let us understand each element involved in this life cycle.
A. Creation of Application objects: To understand this, it's good to write the
Application class by ourselves. Below I have written an application entry point
(a Main () method) that creates a window named Window1 and fires up a new
application. For this create a WPF application and add a class called Startup.cs
to write the below code.
public
class Startup
{
[STAThread]
static void
Main()
{
//Create application
Application app =
new Application();
//Create a main window
Window1 win =
new Window1();
//Lauch the application and show the
window
app.Run(win);
}
}
Explanation of code:
- When we pass a window to the
Application.Run() method, that window is set as the main window and exposed
to our entire application through the Application.MainWindow property.
- The Run () method then fires the
Application.Startup event and shows the main window.
Well we can accomplish the same result with the
other way of coding like below;
// Create the application.
Application app =
new Application();
// Create, assign, and show the main
window.
Window1 win =
new Window1();
app.MainWindow = win;
win.Show();
// Keep the application alive.
app.Run();
Differences between these two approaches are that in the later approach our
application continues running until the main window and every other window is
closed. At that point, the Run () method returns, and any additional code in our
Main () method is executed before the application winds down.
B: Deriving a Custom Application Class: The above approach is not the pattern which Visual Studio follows when we create a new WPF application, well instead, Visual
Studio derives a custom class from the Application class.
The starting point is a XAML template, which is named App.xaml by default.
<Application
x:Class="TestApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
</Application>
The Class attribute is used in XAML to create a class derived from the element.
Thus, this class creates a class that derives from Application, with the name
TestApplication.App in the above example. The application tag not only creates a
custom application class, but it also sets the StartupUri property to identify
the XAML document that represents the main window.
As with windows, the application class is defined in two separate portions that
are fused together at compile time. The automatically generated portion isn't
visible in our project, but it contains the Main () entry point and the code for
starting the application. It looks something like this:
public
partial class
App : Application
{
[STAThread()]
public static
void Main()
{
TestApplication.App app = new
TestApplication.App();
app.InitializeComponent();
app.Run();
}
public void
InitializeComponent()
{
this.StartupUri =
new Uri("Window1.xaml",
System.UriKind.Relative);
}
}
If we're really interested in seeing the custom application class that the XAML
template creates, look for the App.g.cs file in the obj\Debug folder inside our
project directory.
Point to remember: The only difference between the automatically generated code
shown here and a custom application class is that we might create on our own is
that the automatically generated class uses the StartupUri property instead of
setting the MainWindow property or passing the main window as a parameter to the
Run() method.
C. Application Shutdown: Ordinarily, the Application class keeps our application
alive as long as at least one window is still open. If this isn't the behavior
we want, we can adjust the Application.ShutdownMode. If we're instantiating our
Application object by hand, we need to set the ShutdownMode property before we
call Run ().
Let us understand ShutdownMode enums
- OnLastWindowClose: This is the default
behavior—our application keeps running as long as there is at least one
window in existence. If we close the main window, the Application.MainWindow
property still refers to the object that represents the closed window.
- OnMainWindowClose: our application stays
alive only as long as the main window is open. When ShutdownMode is
OnMainWindowClose and we close the main window, the Application object will
automatically close all the other windows before the Run() method returns.
- OnExplicitShutdown: The application never
ends (even if all the windows are closed) unless we call
Application.Shutdown(). This approach might make sense if our application is
a front end for a long-running background task.
So when we want to use the OnMainWindowClose
approach and we're using the App.xaml file, we need to make this addition in the
XAML.
<Application
x:Class="ApplicationLifeCycle.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
ShutdownMode="OnMainWindowClose">
<Application.Resources>
</Application.Resources>
</Application>
No matter what shutdown method we choose, we can always use the Application.
Shutdown() method to end our application immediately.
D. Application events: Initially, the App.xaml.cs file doesn't contain any code.
Although no code is required, we can add code that handles application events.
The Application class provides a small set of useful events which I have
discussed below;
-
Startup: Occurs after the Application.Run()
method is called and just before the main window is shown (if we passed the
main window to the Run() method).
-
Exit: Occurs when the application is being
shut down for any reason, just before the Run() method returns. You can't
cancel the shutdown at this point.
-
SessionEnding: Occurs when the Windows session
is ending—for example, when the user is logging off or shutting down the
computer. You can also cancel the shutdown by setting
SessionEndingCancelEventArgs.Cancel to true. If we don't, WPF will call the
Application.Shutdown() method when our event handler ends.
Lets have a look on how to use this in code;
private
bool unsavedData =
false;
public bool
UnsavedData
{
get {
return unsavedData; }
set { unsavedData =
value; }
}
protected
override void OnStartup(StartupEventArgs
e)
{
base.OnStartup(e);
UnsavedData = true;
}
private
void Application_SessionEnding(object
sender, SessionEndingCancelEventArgs e)
{
base.OnSessionEnding(e);
if (UnsavedData)
{
e.Cancel = true;
MessageBox.Show(
"The application attempted to be closed as a
result of " + e.ReasonSessionEnding.ToString() +
". This is not allowed, as we
have unsaved data.");
}
}
-
Activated: Occurs when one of the windows in
the application gets activated. This occurs when we switch from another
Windows program to this application. It also occurs the firsttime we show a
window.
-
Deactivated: Occurs when a window in the
application gets deactivated. This occurs when we switch to another Windows
program.
-
DispatcherUnhandledException: Occurs when an
unhandled exception occurs anywhere in Your application on the main
application thread. The application dispatcher catches these exceptions. By
responding to this event, we can log critical errors.
private
void
Application_DispatcherUnhandledException(object
sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs
e)
{
MessageBox.Show("An
unhandled " + e.Exception.GetType().ToString() +
"
exception was caught and ignored.");
e.Handled = true;
}
<Application
x:Class="ApplicationLifeCycle.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
DispatcherUnhandledException="Application_DispatcherUnhandledException"
ShutdownMode="OnMainWindowClose"
>
</Application>
Hope It Helped, Cheers.