应用程序管理概述

本主题概述用于创建和管理应用程序的 Windows Presentation Foundation (WPF) 服务。 WPF 应用程序的内核是 Application 类,它支持各种核心应用程序服务。 本主题介绍其中最重要的一些服务。

本主题包括下列各节。

  • 应用程序类
  • 应用程序定义
  • 获取当前的应用程序
  • 应用程序生存期
  • 其他应用程序服务
  • 相关主题

应用程序类

应用程序由很多个特定于应用程序的元素组成,其中包括user interface (UI)、业务逻辑、数据访问逻辑、控件以及数据。 应用程序不同,这些元素通常也不同。 但是,所有应用程序往往都具有一组共同的功能,便于进行应用程序实现和管理。 在 WPF 中,这组共同的应用程序范围功能由 Application 类封装,该类提供下列服务:

  • 创建和管理公共应用程序基础结构。

  • 跟踪应用程序的生存期并与之交互。

  • 检索和处理命令行参数。

  • 共享应用程序范围的属性和资源。

  • 检测和响应未经处理的异常。

  • 返回退出代码。

  • 管理独立应用程序中的窗口(请参见 WPF Windows 概述)。

  • 跟踪和管理导航(请参见导航概述)。

若要在应用程序中使用这些服务,您需要使用 Application 类来实现应用程序定义。

应用程序定义

WPF 应用程序定义是一个从 Application 派生的类,并且使用特殊的 Microsoft build engine (MSBuild) 设置进行配置。

实现应用程序定义

典型的 WPF 应用程序定义通过结合使用标记和代码隐藏来实现。 这使您能够使用标记以声明方式设置应用程序的属性、资源以及注册事件,同时在代码隐藏中处理事件并实现特定于应用程序的行为。

下面的示例演示如何结合使用标记与代码隐藏来实现应用程序定义:

<Application 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
  x:Class="SDKSample.App" />

Imports Microsoft.VisualBasic
Imports System.Windows ' Application

Namespace SDKSample
    Partial Public Class App
        Inherits Application
    End Class
End Namespace
using System.Windows;  // Application

namespace SDKSample
{
    public partial class App : Application { }
}

若要使标记文件和代码隐藏文件能够配合工作,需要满足下列条件:

  • 在标记中,Application 元素必须包含 x:Class 特性。 生成应用程序时,标记文件中如果存在 x:Class,则 MSBuild 将创建一个从 Application 派生的 partial 类,并且该类的名称由 x:Class 特性指定。 这要求添加 XAML 架构的 XML 命名空间声明 (xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml")。

  • 在代码隐藏中,该类必须是 partial 类,其名称由标记中的 x:Class 特性指定,并且该类必须从 Application 派生。 这样,代码隐藏文件就与应用程序生成时为标记文件生成的 partial 类相关联(请参见生成 WPF 应用程序 (WPF))。

注意注意

在使用 Microsoft Visual Studio 创建新的 WPF 应用程序项目或 WPF 浏览器应用程序项目时,默认情况下会将应用程序定义包括在内并结合使用标记和代码隐藏来对其进行定义。

此类代码是实现应用程序定义的最低要求。 但是,若要生成并运行应用程序,需要对应用程序定义进行额外的 MSBuild 配置。

针对 MSBuild 配置应用程序定义

独立应用程序和 XAML browser applications (XBAPs) 要求实现某种级别的基础结构才能运行。 该基础结构最重要的部分是入口点。 当用户启动应用程序时,操作系统会调用入口点,入口点是一个用于启动应用程序的众所周知的函数。

传统上,根据所用技术的不同,开发人员一直需要自己编写部分或全部此类代码。 但是,当应用程序定义的标记文件被配置为 MSBuild ApplicationDefinition 项时,WPF 将为您生成此类代码,如下面的 MSBuild 项目文件中所示:

<Project 
  DefaultTargets="Build"
  xmlns="https://schemas.microsoft.com/developer/msbuild/2003">
  ...
  <ApplicationDefinition Include="App.xaml" />
  <Compile Include="App.xaml.cs" />
  ...
</Project>

由于代码隐藏文件包含代码,因此按照惯例将它标记为 MSBuild Compile 项。

对应用程序定义的标记和代码隐藏文件应用这些 MSBuild 配置会使 MSBuild 生成如下所示的代码:


Imports Microsoft.VisualBasic
Imports System ' STAThread
Imports System.Windows ' Application

Namespace SDKSample
    Public Class App
        Inherits Application
        Public Sub New()
        End Sub
        <STAThread>
        Public Shared Sub Main()
            ' Create new instance of application subclass
            Dim app As New App()

            ' Code to register events and set properties that were
            ' defined in XAML in the application definition
            app.InitializeComponent()

            ' Start running the application
            app.Run()
        End Sub

        Public Sub InitializeComponent()


...


        End Sub
    End Class
End Namespace
using System; // STAThread
using System.Windows; // Application

namespace SDKSample
{
    public class App : Application
    {
        public App() { }
        [STAThread]
        public static void Main()
        {
            // Create new instance of application subclass
            App app = new App();

            // Code to register events and set properties that were
            // defined in XAML in the application definition
            app.InitializeComponent();

            // Start running the application
            app.Run();
        }

        public void InitializeComponent()
        {


...


        }
    }
}

生成的代码使用附加的基础结构代码扩充了应用程序定义,这些代码包括入口点方法 Main。 STAThreadAttribute 属性被应用于 Main 方法以指示 WPF 应用程序的主 UI 线程是一个 STA 线程,此线程是 WPF 应用程序所必需的。当 Main 被调用时,它将创建 App 的一个新实例,然后调用 InitializeComponent 方法来注册事件并设置在标记中实现的属性。 因为系统已为您生成 InitializeComponent,所以您无需像对 PageWindow 实现所做的那样从应用程序定义中显式调用 InitializeComponent。 最后,调用 Run 方法以启动应用程序。

获取当前的应用程序

由于在整个应用程序中共享 Application 类的服务,因此对于每个 AppDomain,可以只有一个 Application 类实例。 为了实施这一点,系统将 Application 类实现为单一实例类(请参见 Implementing Singleton in C#(在 C# 中实现单一实例),该类使用 static Current 属性创建自身的单一实例并提供对该实例的共享访问。

下面的代码显示对于当前的 AppDomain,如何获得对 Application 对象的引用。

            ' Get current application
            Dim current As Application = App.Current
// Get current application
Application current = App.Current;

Current 返回对 Application 类的实例的引用。 如果需要对 Application 派生类的引用,必须强制转换 Current 属性的值,如下面的示例中所示。

            ' Get strongly-typed current application
            Dim appCurrent As App = CType(App.Current, App)
// Get strongly-typed current application
App app = (App)App.Current;

可以在 Application 对象生存期中的任何时刻检查 Current 的值。 但您应该十分谨慎。 在实例化 Application 类之后, Application 对象的状态会在一段时间内不一致。 在此时间段内,Application 执行代码运行所需的各种初始化任务,其中包括建立应用程序基础结构、设置属性以及注册事件。 如果您在此期间尝试使用 Application 对象,代码可能会有意外的结果,特别是当代码依赖于设置各种 Application 属性时。

Application 完成其初始化任务后,其生存期才真正开始。

应用程序生存期

WPF 应用程序生存期由 Application 所引发的几个事件来标记,这些事件告诉您应用程序何时启动、何时激活和停用以及何时关闭。

本节包含下列子节。

  • 初始屏幕
  • 启动应用程序
  • 显示用户界面
  • 处理命令行参数
  • 激活与停用应用程序
  • 应用程序关闭
  • 未经处理的异常
  • 应用程序生存期事件

初始屏幕

当在 .NET Framework 3.5 SP1 中启动时,您可以指定要在启动窗口中使用的图像或“初始屏幕”。 通过使用 SplashScreen 类,可以在应用程序加载时轻松地显示启动窗口。 调用 Run 之前将创建和显示 SplashScreen 窗口。 有关更多信息,请参见应用程序启动时间如何:将初始屏幕添加到 WPF 应用程序

启动应用程序

在调用 Run 并且初始化应用程序之后,就可以运行应用程序了。 此时刻表示 Startup 事件的引发时间:


Imports Microsoft.VisualBasic
Imports System.Windows ' Application, StartupEventArgs, WindowState

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            ' Application is running


...


        End Sub
    End Class
End Namespace
using System.Windows; // Application, StartupEventArgs, WindowState

namespace SDKSample
{
    public partial class App : Application
    {
        void App_Startup(object sender, StartupEventArgs e)
        {
            // Application is running


...


        }
    }
}

在应用程序生存期中的这一时刻,所要做的最常见的一件事情是显示 UI。

显示用户界面

大多数独立 Windows 应用程序在开始运行时会打开一个 Window。 可以在 Startup 事件处理程序中执行此操作,如下面的代码所示。

<Application
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App" 
  Startup="App_Startup" />

Imports Microsoft.VisualBasic
Imports System.Windows ' Application, StartupEventArgs

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            ' Open a window
            Dim window As New MainWindow()
            window.Show()
        End Sub
    End Class
End Namespace
using System.Windows; // Application, StartupEventArgs

namespace SDKSample
{
    public partial class App : Application
    {
        void App_Startup(object sender, StartupEventArgs e)
        {
            // Open a window
            MainWindow window = new MainWindow();
            window.Show();
        }
    }
}
注意注意

默认情况下,在独立应用程序中实例化的第一个 Window 成为主应用程序窗口。此 Window 对象由 Application.MainWindow 属性引用。如果要使用与实例化的第一个 Window 不同的窗口作为主窗口,可以使用编程方式更改 MainWindow 属性的值。

当 XBAP 首次启动时,它很可能导航到 Page。 下面的代码对此进行演示。

<Application 
  x:Class="SDKSample.App"
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  Startup="App_Startup" />

Imports System ' Uri, UriKind, EventArgs, Console
Imports System.Windows ' Application, StartupEventArgs
Imports System.Windows.Navigation ' NavigationWindow

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            CType(Me.MainWindow, NavigationWindow).Navigate(New Uri("HomePage.xaml", UriKind.Relative))
        End Sub
    End Class
End Namespace
using System; // Uri, UriKind, EventArgs, Console
using System.Windows; // Application, StartupEventArgs
using System.Windows.Navigation; // NavigationWindow

namespace SDKSample
{
    public partial class App : Application
    {        
        void App_Startup(object sender, StartupEventArgs e)
        {
            ((NavigationWindow)this.MainWindow).Navigate(new Uri("HomePage.xaml", UriKind.Relative));
        }
    }
}

如果您处理 Startup 的目的只是为了打开 Window 或导航到 Page,则可以改为在标记中设置 StartupUri 特性。

下面的示例演示如何从独立应用程序中使用 StartupUri 以打开 Window

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="MainWindow.xaml" />

下面的示例演示如何从 XBAP 中使用 StartupUri 以导航到 Page

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="HomePage.xaml" />

此标记与前面用于打开窗口的代码具有相同的效果。

注意注意

有关导航的更多信息,请参见导航概述

如果需要使用非默认的构造函数来实例化 Window,或者需要在显示它之前设置它的属性或订阅它的事件,则需要处理 Startup 事件来打开它。

处理命令行参数

在 Windows 中,可以从命令提示符处或桌面启动独立应用程序。 在这两种情况下,都可以将命令行参数传递到应用程序。下面的示例演示一个使用单个命令行参数“/StartMinimized”启动的应用程序:

wpfapplication.exe /StartMinimized

在应用程序初始化过程中,WPF 从操作系统检索命令行参数,然后通过 StartupEventArgs 参数的 Args 属性将这些命令行参数传递到 Startup 事件处理程序。 可以使用以下代码来检索和存储命令行参数。

<Application
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App"
  Startup="App_Startup" />

Imports Microsoft.VisualBasic
Imports System.Windows ' Application, StartupEventArgs, WindowState

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            ' Application is running
            ' Process command line args
            Dim startMinimized As Boolean = False
            Dim i As Integer = 0
            Do While i <> e.Args.Length
                If e.Args(i) = "/StartMinimized" Then
                    startMinimized = True
                End If
                i += 1
            Loop

            ' Create main application window, starting minimized if specified
            Dim mainWindow As New MainWindow()
            If startMinimized Then
                mainWindow.WindowState = WindowState.Minimized
            End If
            mainWindow.Show()
        End Sub
    End Class
End Namespace
using System.Windows; // Application, StartupEventArgs, WindowState

namespace SDKSample
{
    public partial class App : Application
    {
        void App_Startup(object sender, StartupEventArgs e)
        {
            // Application is running
            // Process command line args
            bool startMinimized = false;
            for (int i = 0; i != e.Args.Length; ++i)
            {
                if (e.Args[i] == "/StartMinimized")
                {
                    startMinimized = true;
                }
            }

            // Create main application window, starting minimized if specified
            MainWindow mainWindow = new MainWindow();
            if (startMinimized)
            {
                mainWindow.WindowState = WindowState.Minimized;
            }
            mainWindow.Show();
        }
    }
}

这段代码处理 Startup 以检查是否提供了 /StartMinimized 命令行参数;如果提供了此参数,则打开 WindowStateMinimized 的主窗口。 请注意,由于 WindowState 属性必须以编程方式进行设置,因此必须在代码中显式打开主 Window

XBAPs 无法检索和处理命令行参数,因为它们是使用 ClickOnce 部署(请参见部署 WPF 应用程序 (WPF))启动的。 但是,这些应用程序可以通过用于启动它们的 URL 来获取和处理查询字符串形参。

激活与停用应用程序

用户使用 Windows 可以在应用程序之间进行切换。最常用的方法是使用 Alt+Tab 组合键。 仅当应用程序具有用户可选择的可见的 Window 时,才能切换到该应用程序。 当前选定的 Window 是“活动窗口”(也称为前台窗口),并且是接收用户输入的 Window。具有活动窗口的应用程序为“活动应用程序”(即前台应用程序)。在下列情况下,应用程序将成为活动应用程序:

  • 应用程序启动并显示一个 Window

  • 用户通过在应用程序中选择一个 Window 从另一个应用程序切换过来。

可以通过处理 Application.Activated 事件来检测应用程序何时成为活动应用程序。

与此类似,在下列情况下,应用程序成为非活动应用程序:

  • 用户从当前应用程序切换到另一个应用程序。

  • 应用程序关闭。

可以通过处理 Application.Deactivated 事件来检测应用程序何时成为非活动应用程序。

下面的代码演示如何处理 ActivatedDeactivated 事件以确定应用程序是否为活动应用程序。

<Application 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App"
  StartupUri="MainWindow.xaml"
  Activated="App_Activated" 
  Deactivated="App_Deactivated" />

Imports Microsoft.VisualBasic
Imports System ' EventArgs
Imports System.Windows ' Application

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private isApplicationActive As Boolean

        Private Sub App_Activated(ByVal sender As Object, ByVal e As EventArgs)
            ' Application activated
            Me.isApplicationActive = True
        End Sub

        Private Sub App_Deactivated(ByVal sender As Object, ByVal e As EventArgs)
            ' Application deactivated
            Me.isApplicationActive = False
        End Sub
    End Class
End Namespace
using System; // EventArgs
using System.Windows; // Application

namespace SDKSample
{
    public partial class App : Application
    {
        bool isApplicationActive;

        void App_Activated(object sender, EventArgs e)
        {
            // Application activated
            this.isApplicationActive = true;
        }

        void App_Deactivated(object sender, EventArgs e)
        {
            // Application deactivated
            this.isApplicationActive = false;
        }
    }
}

还可以激活和停用 Window。 有关更多信息,请参见Window.ActivatedWindow.Deactivated

注意注意

Application.ActivatedApplication.Deactivated 都不会对 XBAPs 引发。

应用程序关闭

应用程序关闭时,其生存期就结束了。应用程序可能由于下列原因而关闭:

  • 用户关闭了所有 Window

  • 用户关闭了主 Window

  • 用户通过注销或关闭来终止 Windows 会话。

  • 满足特定于应用程序的条件。

为了帮助您管理应用程序关闭,Application 提供了 Shutdown 方法、ShutdownMode 属性以及 SessionEndingExit 事件。

注意注意

只能从具有 UIPermission 的应用程序调用 Shutdown。独立 WPF 应用程序始终具有该权限。但是,在 Internet 区域中的部分信任安全沙盒中运行的 XBAPs 不具有该权限。

关闭模式

大多数应用程序在所有窗口关闭或主窗口关闭时都会关闭。 但有时其他特定于应用程序的条件可能决定应用程序何时关闭。 可以通过使用以下 ShutdownMode 枚举值之一设置 ShutdownMode 来指定应用程序关闭的条件:

ShutdownMode 的默认值为 OnLastWindowClose,该值表示应用程序将在用户关闭应用程序中的最后一个窗口时自动关闭。 但是,如果应用程序应当在主窗口关闭时关闭,并且您将 ShutdownMode 设置为 OnMainWindowClose,那么 WPF 会自动关闭。 下面的示例对此进行演示。

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App"
    ShutdownMode="OnMainWindowClose" />

如果您具有特定于应用程序的关闭条件,请将 ShutdownMode 设置为 OnExplicitShutdown。 在这种情况下,您应当通过显式调用 Shutdown 方法来关闭应用程序;否则,即使所有窗口都已关闭,应用程序仍将继续运行。 请注意,当 ShutdownModeOnLastWindowCloseOnMainWindowClose 时,将会隐式调用 Shutdown

注意注意

可以从 XBAP 中设置 ShutdownMode,但此设置将被忽略;当在浏览器中通过导航而离开 XBAP 时,或者当承载 XBAP 的浏览器关闭时,将总是关闭该应用程序。有关更多信息,请参见导航概述

会话终止

ShutdownMode 属性所描述的关闭条件是特定于应用程序的。 但在某些情况下,应用程序可能会由于外部条件而关闭。 最常见的外部条件出现在用户通过以下操作终止 Windows 会话时:

  • 注销

  • 关机

  • 重新启动

  • 休眠

若要检测 Windows 会话的终止时间,可以处理 SessionEnding 事件,如下面的示例所示。

<Application 
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App"
    StartupUri="MainWindow.xaml"
    SessionEnding="App_SessionEnding" />

Imports Microsoft.VisualBasic
Imports System.Windows ' Application, SessionEndingCancelEventArgs, MessageBox, MessageBoxResult, MessageBoxButton

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_SessionEnding(ByVal sender As Object, ByVal e As SessionEndingCancelEventArgs)
            ' Ask the user if they want to allow the session to end
            Dim msg As String = String.Format("{0}. End session?", e.ReasonSessionEnding)
            Dim result As MessageBoxResult = MessageBox.Show(msg, "Session Ending", MessageBoxButton.YesNo)

            ' End session, if specified
            If result = MessageBoxResult.No Then
                e.Cancel = True
            End If
        End Sub
    End Class
End Namespace
using System.Windows; // Application, SessionEndingCancelEventArgs, MessageBox, MessageBoxResult, MessageBoxButton

namespace SDKSample
{
    public partial class App : Application
    {
        void App_SessionEnding(object sender, SessionEndingCancelEventArgs e)
        {
            // Ask the user if they want to allow the session to end
            string msg = string.Format("{0}. End session?", e.ReasonSessionEnding);
            MessageBoxResult result = MessageBox.Show(msg, "Session Ending", MessageBoxButton.YesNo);

            // End session, if specified
            if (result == MessageBoxResult.No)
            {
                e.Cancel = true;
            }
        }
    }
}

在此示例中,代码检查 ReasonSessionEnding 属性以确定 Windows 会话的结束方式。 代码使用该值向用户显示一个确认消息。 如果用户不希望终止会话,则代码会将 Cancel 设置为 true 以阻止 Windows 会话终止。

注意注意

SessionEnding 不会对 XBAPs 引发。

Exit

当应用程序关闭时,它可能需要执行一些最终处理,例如保存应用程序状态。 对于这些情况,您可以处理 Exit 事件。

<Application
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App"
    StartupUri="MainWindow.xaml" 
    Startup="App_Startup" 
    Exit="App_Exit">


...


</Application>
Imports System.IO ' StreamReader, FileMode
Imports System.IO.IsolatedStorage ' IsolatedStorageFile, IsolatedStorageFileStream

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private filename As String = "App.txt"



...


        Private Sub App_Exit(ByVal sender As Object, ByVal e As ExitEventArgs)
            ' Persist application-scope property to isolated storage
            Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForDomain()
            Using stream As New IsolatedStorageFileStream(filename, FileMode.Create, storage)
            Using writer As New StreamWriter(stream)
                ' Persist each application-scope property individually
                For Each key As String In Me.Properties.Keys
                    writer.WriteLine("{0},{1}", key, Me.Properties(key))
                Next key
            End Using
            End Using
        End Sub
    End Class
End Namespace
using System.Windows; // Application, StartupEventArgs
using System.IO; // StreamReader, FileMode
using System.IO.IsolatedStorage; // IsolatedStorageFile, IsolatedStorageFileStream

namespace SDKSample
{
    public partial class App : Application
    {
        string filename = "App.txt";



...


        private void App_Exit(object sender, ExitEventArgs e)
        {
            // Persist application-scope property to isolated storage
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filename, FileMode.Create, storage))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                // Persist each application-scope property individually
                foreach (string key in this.Properties.Keys)
                {
                    writer.WriteLine("{0},{1}", key, this.Properties[key]);
                }
            }
        }
    }
}

有关完整的示例,请参见如何:跨应用程序会话保持和还原应用程序范围的属性

独立应用程序和 XBAPs 都可以处理 Exit。 对于 XBAPs,在下列情况下会引发 Exit

  • 离开一个 XBAP。

  • 在 Internet Explorer 7 中,关闭了承载 XBAP 的选项卡。

  • 关闭了浏览器。

退出代码

应用程序通常由操作系统响应用户请求而启动。 但是,应用程序也可以由执行某个特定任务的其他应用程序启动。 当被启动的应用程序关闭时,启动它的应用程序可能想知道被启动的应用程序的关闭条件。 在这些情况下,Windows 允许应用程序在关闭时返回应用程序退出代码。 默认情况下,WPF 应用程序返回一个值为 0 的退出代码。

注意注意

如果您在 Visual Studio 中进行调试,应用程序退出代码会在应用程序关闭时显示在“输出”窗口中的如下所示的消息中:

The program '[5340] AWPFApp.vshost.exe: Managed' has exited with code 0 (0x0).

通过单击“视图”菜单上的“输出”可打开“输出”窗口。

若要更改输出代码,可以调用 Shutdown(Int32) 重载,该重载接受整数参数作为退出代码:

' Shutdown and return a non-default exit code
Application.Current.Shutdown(-1)
// Shutdown and return a non-default exit code
Application.Current.Shutdown(-1);

可以通过处理 Exit 事件来检测和更改退出代码的值。 Exit 事件处理程序接受一个传递给它的 ExitEventArgs,该参数通过 ApplicationExitCode 属性提供对退出代码的访问。 有关更多信息,请参见 Exit

注意注意

在独立应用程序和 XBAPs 中都可以设置退出代码。但是,XBAPs 将忽略退出代码值。

未经处理的异常

有时,应用程序可能在非正常条件下关闭,例如当引发意外的异常时。 在此情况下,应用程序可能没有代码来检测和处理异常。 这种类型的异常是未经处理的异常;在应用程序关闭之前,将显示一个如下图所示的通知。

未经处理的异常通知

从用户体验的角度来说,应用程序最好通过执行以下部分或全部操作来避免这一默认行为:

  • 显示用户友好的信息。

  • 尝试使应用程序继续运行。

  • 在 Windows 事件日志中以开发人员易于理解的方式详细记录异常信息。

实现此支持的前提是能够检测到未经处理的异常(对于该异常将引发 DispatcherUnhandledException 事件)。

<Application
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App"
  StartupUri="MainWindow.xaml"
  DispatcherUnhandledException="App_DispatcherUnhandledException" />

Imports Microsoft.VisualBasic
Imports System.Windows ' Application
Imports System.Windows.Threading ' DispatcherUnhandledExceptionEventArgs

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_DispatcherUnhandledException(ByVal sender As Object, ByVal e As DispatcherUnhandledExceptionEventArgs)
            ' Process unhandled exception


...


            ' Prevent default unhandled exception processing
            e.Handled = True
        End Sub
    End Class
End Namespace
using System.Windows; // Application
using System.Windows.Threading; // DispatcherUnhandledExceptionEventArgs

namespace SDKSample
{
    public partial class App : Application
    {
        void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            // Process unhandled exception


...


            // Prevent default unhandled exception processing
            e.Handled = true;
        }
    }
}

DispatcherUnhandledException 事件处理程序接受一个传递给它的 DispatcherUnhandledExceptionEventArgs 参数,该参数包含关于未经处理的异常的上下文信息,其中包括异常本身 (DispatcherUnhandledExceptionEventArgs.Exception)。 使用该信息可以确定如何处理异常。

在处理 DispatcherUnhandledException 时,应当将 DispatcherUnhandledExceptionEventArgs.Handled 属性设置为 true;否则,WPF 仍会将异常视为未经处理的异常,并恢复前面描述的默认行为。 如果引发未经处理的异常,并且或者 DispatcherUnhandledException 事件未被处理,或者该事件被处理但 Handled 被设置为 false,则应用程序会立即关闭。 而且,不会再引发其他 Application 事件。 因此,如果应用程序具有必须在应用程序关闭之前运行的代码,则需要处理 DispatcherUnhandledException

尽管应用程序可能会由于未经处理的异常而关闭,但应用程序通常是为响应用户请求而关闭的,如下一节所述。

应用程序生存期事件

独立应用程序和 XBAPs 的生存期不完全相同。下图说明了独立应用程序的生存期中的关键事件,并显示这些事件的引发顺序。

独立应用程序 - 应用程序对象事件

同样,下图说明了 XBAP 的生存期中的关键事件,并显示这些事件的引发顺序。

XBAP - 应用程序对象事件

其他应用程序服务

除了管理应用程序的生存期以外,Application 还提供其他一些服务,包括:

  • 共享的应用程序范围属性。

  • 共享的应用程序范围资源。

  • 应用程序资源、内容和源站点数据文件。

  • 窗口管理。

  • 导航管理。

共享的应用程序范围属性

应用程序提供 Properties 属性来公开可以在应用程序范围内共享的状态。 下面提供了一个使用 Properties 的示例:

      ' Set an application-scope property with a custom type
      Dim customType As New CustomType()
      Application.Current.Properties("CustomType") = customType


...


      ' Get an application-scope property
      ' NOTE: Need to convert since Application.Properties is a dictionary of System.Object
      Dim customType As CustomType = CType(Application.Current.Properties("CustomType"), CustomType)
// Set an application-scope property with a custom type
CustomType customType = new CustomType();
Application.Current.Properties["CustomType"] = customType;


...


// Get an application-scope property
// NOTE: Need to convert since Application.Properties is a dictionary of System.Object
CustomType customType = (CustomType)Application.Current.Properties["CustomType"];

有关更多信息,请参见以下内容:

共享的应用程序范围资源

应用程序提供了 Resources 属性,以使开发人员可以在应用程序内共享 UI 资源。 下面提供了一个使用 Resources 的示例:

      ' Set an application-scope resource
      Application.Current.Resources("ApplicationScopeResource") = Brushes.White


...


      ' Get an application-scope resource
      Dim whiteBrush As Brush = CType(Application.Current.Resources("ApplicationScopeResource"), Brush)
// Set an application-scope resource
Application.Current.Resources["ApplicationScopeResource"] = Brushes.White;


...


// Get an application-scope resource
Brush whiteBrush = (Brush)Application.Current.Resources["ApplicationScopeResource"];

有关更多信息,请参见以下内容:

应用程序资源、内容和源站点数据文件

WPF 应用程序可以管理多种类型的非代码数据文件,包括资源文件、内容文件和源站点文件。 下面的帮助器方法可用于加载这些类型的数据文件:

窗口管理

ApplicationWindow 之间具有密切关系。 正如您所看到的,应用程序的生存期可能取决于其窗口的生存期,如 ShutdownMode 属性中所指定的那样。 Application 记录哪个窗口被指定为主应用程序窗口 (Application.MainWindow),并维护当前已实例化的窗口的列表 (Application.Windows)。

有关更多信息,请参见 WPF Windows 概述

导航管理

对于具有导航功能(使用 NavigationWindowFrame)的独立应用程序或 XBAPs,Application 检测应用程序内的任何导航操作,并在适当的时候引发下列事件:

此外,Application 使任何类型的应用程序都能够使用 GetCookieSetCookie 来创建、保存和检索 Cookie。

有关更多信息,请参见导航概述

请参见

参考

Application

概念

WPF Windows 概述

导航概述

WPF 应用程序资源、内容和数据文件

WPF 中的 Pack URI

应用程序开发

其他资源

应用程序模型:帮助主题