애플리케이션 관리 개요

모든 애플리케이션은 애플리케이션 구현 및 관리에 적용하는 일반적인 기능 집합을 공유하는 경향이 있습니다. 이 토픽에서는 애플리케이션을 만들고 관리하는 Application 클래스의 기능에 대해 간략하게 설명합니다.

Application 클래스

WPF에서 일반적인 애플리케이션 범위 기능은 Application 클래스에 캡슐화됩니다. Application 클래스는 다음과 같은 기능을 포함하고 있습니다.

  • 애플리케이션 수명 추적 및 상호 작용

  • 명령줄 매개 변수 검색 및 처리

  • 처리되지 않은 예외의 검색 및 응답

  • 애플리케이션 범위 속성 및 리소스 공유

  • 독립 실행형 애플리케이션에서 창 관리

  • 탐색 추적 및 관리

Application 클래스를 사용하여 일반적인 작업을 수행하는 방법

Application 클래스에 대해 자세히 알 필요가 없는 경우 다음 표에 Application의 몇 가지 일반 작업과 이러한 작업을 수행하는 방법이 나열되어 있습니다. 관련 API 및 항목을 확인하여 추가 정보 및 샘플 코드를 찾을 수 있습니다.

Task 접근 방식
현재 애플리케이션을 나타내는 개체 가져오기 Application.Current 속성을 사용합니다.
애플리케이션에 시작 화면 추가 WPF 애플리케이션에 시작 화면 추가를 참조하세요.
애플리케이션 시작 Application.Run 메서드를 사용합니다.
애플리케이션 중지 Application.Current 개체의 Shutdown 메서드를 사용합니다.
명령줄에서 인수 가져오기 Application.Startup 이벤트를 처리하고 StartupEventArgs.Args 속성을 사용합니다. 예제를 보려면 Application.Startup 이벤트를 참조하세요.
애플리케이션 종료 코드 가져오기 및 설정 Application.Exit 이벤트 처리기에서 ExitEventArgs.ApplicationExitCode 속성을 설정하거나 Shutdown 메서드를 호출하고 정수를 전달합니다.
처리되지 않은 예외의 검색 및 응답 DispatcherUnhandledException 이벤트를 처리합니다.
애플리케이션 범위 리소스 가져오기 및 설정 Application.Resources 속성을 사용합니다.
애플리케이션 범위 리소스 사전 사용 애플리케이션 범위 리소스 사전 사용을 참조하세요.
애플리케이션 범위 속성 가져오기 및 설정 Application.Properties 속성을 사용합니다.
애플리케이션 상태 가져오기 및 저장 애플리케이션 세션 간의 애플리케이션 범위 속성 유지 및 복원을 참조하세요.
리소스 파일, 콘텐츠 파일 및 원본 사이트 파일을 포함하여 비코드 데이터 파일 관리 WPF 애플리케이션 리소스, 콘텐츠 및 데이터 파일을 참조하세요.
독립 실행형 애플리케이션의 창 관리 WPF 창 개요를 참조하세요.
탐색 추적 및 관리 탐색 개요를 참조하세요.

애플리케이션 정의

Application 클래스의 기능을 활용하려면 애플리케이션 정의를 구현해야 합니다. WPF 애플리케이션 정의는 Application에서 파생되는 클래스이며 특수한 MSBuild 설정으로 구성됩니다.

애플리케이션 정의 구현

일반적인 WPF 애플리케이션 정의는 태그 및 코드 숨김을 모두 사용하여 구현됩니다. 따라서 코드 숨김에서 애플리케이션별 동작을 구현하고 이벤트를 처리하는 동시에 태그를 사용하여 애플리케이션 속성과 리소스를 선언적으로 설정하고 이벤트를 등록할 수 있습니다.

다음 예제에서는 태그 및 코드 숨김을 모두 사용하여 애플리케이션 정의를 구현하는 방법을 보여 줍니다.

<Application 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  x:Class="SDKSample.App" />
using System.Windows;

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

Imports System.Windows

Namespace SDKSample
    Partial Public Class App
        Inherits Application
    End Class
End Namespace

태그 파일과 코드 숨김 파일이 함께 작동하도록 하려면 다음이 필요합니다.

  • 태그에서 Application 요소에는 x:Class 특성이 포함되어야 합니다. 애플리케이션을 빌드할 때 태그 파일에 x:Class가 있으면 MSBuild는 Application에서 파생되며 x:Class 특성에 의해 이름이 지정되는 partial 클래스를 만듭니다. 이를 위해서는 XAML 스키마(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml")의 XML 네임스페이스 선언을 추가해야 합니다.

  • 코드 숨김에서 클래스는 태그의 x:Class 특성으로 지정된 이름과 같은 이름을 가진 partial 클래스여야 하며 Application에서 파생되어야 합니다. 이를 통해 애플리케이션 빌드 시 태그 파일에 대해 생성되는 partial 클래스와 코드 숨김 파일을 연결할 수 있습니다(WPF 애플리케이션 빌드 참조).

참고

Visual Studio를 사용하여 새 WPF 애플리케이션 프로젝트나 WPF 브라우저 애플리케이션 프로젝트를 만들면 애플리케이션 정의가 기본적으로 포함되고 태그와 코드 숨김을 모두 사용하여 정의됩니다.

이 코드는 애플리케이션 정의를 구현하는 데 필요한 최소한의 코드이지만, 애플리케이션을 빌드하고 실행하려면 먼저 애플리케이션 정의에 대해 추가 MSBuild 구성이 이루어져야 합니다.

MSBuild용 애플리케이션 정의 구성

독립 실행형 애플리케이션과 XAML(Extensible Application Markup Language)을 실행하려면 특정 수준의 인프라를 구현해야 합니다. 이 인프라의 가장 중요한 부분은 진입점입니다. 사용자가 애플리케이션을 시작하면 운영 체제에서는 잘 알려진 애플리케이션 시작 함수인 진입점을 호출합니다.

Warning

XBAP를 사용하려면 Internet Explorer 및 Firefox와 같은 레거시 브라우저가 작동해야 합니다. 이러한 이전 브라우저 버전은 일반적으로 Windows 10 및 Windows 11에서 지원되지 않습니다. 최신 브라우저는 보안 위험으로 인해 XBAP 앱에 필요한 기술을 더 이상 지원하지 않습니다. XBAP를 사용하도록 설정하는 플러그 인은 더 이상 지원되지 않습니다.

일반적으로는 기술에 따라 개발자가 직접 이 코드 일부나 전체를 작성해야 합니다. 하지만 다음 MSBuild 프로젝트 파일에서 볼 수 있는 것처럼 애플리케이션 정의의 태그 파일을 MSBuild ApplicationDefinition 항목으로 구성하면 WPF에서 이 코드가 자동으로 생성됩니다.

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

코드 숨김 파일에 코드가 들어 있으므로 이 코드는 정상적으로 MSBuild Compile 항목으로 표시됩니다.

애플리케이션 정의의 태그 및 코드 숨김 파일에 이러한 MSBuild 구성을 적용하면 MSBuild에서 다음과 같은 코드가 생성됩니다.

using System;
using System.Windows;

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()
        {
            // Initialization code goes here.
        }
    }
}
Imports System.Windows

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()
            ' Initialization code goes here.	
        End Sub
    End Class
End Namespace

결과 코드는 진입점 메서드인 Main을 포함하는 추가 인프라 코드로 애플리케이션 정의를 보강합니다. STAThreadAttribute 특성은 Main메서드에 적용되어 WPF 애플리케이션에 대한 기본 UI 스레드가 WPF 애플리케이션에 필요한 STA 스레드임을 나타냅니다. Main은 호출되면 새 App 인스턴스를 생성한 후 이벤트를 등록하고 태그에서 구현되는 속성을 설정하는 InitializeComponent 메서드를 호출합니다. InitializeComponent가 자동으로 생성되기 때문에 PageWindow 구현에서 하는 것처럼 애플리케이션 정의에서 InitializeComponent를 명시적으로 호출할 필요가 없습니다. 마지막으로, Run 메서드가 호출되어 애플리케이션을 시작합니다.

현재 애플리케이션 가져오기

Application 클래스의 기능은 애플리케이션 간에 공유되므로 AppDomain 하나당 Application 클래스 인스턴스 하나만 허용됩니다. 이를 강제하기 위해 Application 클래스는 singleton 클래스로 구현됩니다(C#에서 Singleton 구현 참조). singleton 클래스는 자체적인 단일 인스턴스를 만들고 staticCurrent 속성으로 해당 인스턴스에 대한 공유 액세스를 제공합니다.

다음 코드는 현재 AppDomainApplication 개체에 대한 참조를 가져오는 방법을 보여줍니다.

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

CurrentApplication 클래스의 인스턴스에 대한 참조를 반환합니다. Application 파생 클래스를 참조하려면 다음 예제와 같이 Current 속성 값을 캐스팅해야 합니다.

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

Application 개체의 수명 중 언제라도 Current 값을 검사할 수 있습니다. 하지만 이러한 검사를 수행할 때는 주의해야 합니다. Application 클래스가 인스턴스화된 후 Application 개체의 상태가 일치하지 않는 기간이 존재하기 때문입니다. 이 기간 중에는 Application이 애플리케이션 인프라 설정, 속성 설정, 이벤트 등록을 비롯하여 코드를 실행하는 데 필요한 다양한 초기화 작업을 수행합니다. 이 기간 중에 Application 개체를 사용하려고 하면 코드가 예기치 않은 결과를 반환할 수 있습니다. 특히 코드가 설정 중인 다양한 Application 속성에 의해 달라지는 경우에 그렇습니다.

Application이 초기화 작업을 완료하면 실제 수명이 시작됩니다.

애플리케이션 수명

WPF 애플리케이션의 수명은 Application에 의해 발생되는 몇 가지 이벤트로 표시되므로 애플리케이션의 시작 시점, 활성화 및 비활성화 시점, 종료 시점을 알 수 있습니다.

시작 화면

.NET Framework 3.5 SP1부터는 시작 창 또는 시작 화면에 사용할 이미지를 지정할 수 있습니다. SplashScreen 클래스를 사용하면 애플리케이션이 로드되는 동안 손쉽게 시작 창을 표시할 수 있습니다. SplashScreen 창은 Run이 호출되기 전에 만들어져 표시됩니다. 자세한 내용은 애플리케이션 시작 시간WPF 애플리케이션에 시작 화면 추가를 참조하세요.

애플리케이션 시작

Run이 호출되고 애플리케이션이 초기화된 후에는 애플리케이션을 실행할 수 있습니다. 이 시점은 Startup 이벤트가 발생하는 시점입니다.

using System.Windows;

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

Namespace SDKSample
    Partial Public Class App
        Inherits Application
        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            ' Application is running
            '</SnippetStartupCODEBEHIND1>
    End Class
End Namespace
'</SnippetStartupCODEBEHIND2>

애플리케이션 수명 중 이 시점에서 가장 일반적으로 수행되는 작업은 UI를 표시하는 것입니다.

사용자 인터페이스 표시

대부분의 독립 실행형 Windows 애플리케이션은 실행이 시작되면 Window를 엽니다. 다음 코드에 나온 것처럼 Startup 이벤트 처리기가 이 작업을 수행할 수 있는 하나의 위치입니다.

<Application
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App" 
  Startup="App_Startup" />
using System.Windows;

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

Imports System.Windows

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

참고

독립 실행형 애플리케이션에서 처음 인스턴스화되는 Window가 기본적으로 기본 애플리케이션 창이 됩니다. 이 Window 개체는 Application.MainWindow 속성에서 참조됩니다. 처음 인스턴스화된 Window 대신 다른 창이 주 창이 되어야 하는 경우 MainWindow 속성 값을 프로그래밍 방식으로 변경할 수 있습니다.

XBAP를 처음 시작하면 대부분 Page로 이동합니다. 다음 코드에서 이를 확인할 수 있습니다.

<Application 
  x:Class="SDKSample.App"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Startup="App_Startup" />
using System;
using System.Windows;
using System.Windows.Navigation;

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

Imports System.Windows
Imports System.Windows.Navigation

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

Startup을 처리하여 Window만 열거나 Page로 이동하려는 경우에는 태그에서 StartupUri 특성을 대신 설정하면 됩니다.

다음 예제에서는 독립 실행형 애플리케이션에서 StartupUri를 사용하여 Window를 여는 방법을 보여줍니다.

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

다음 예제에서는 XBAP에서 StartupUri를 사용하여 Page로 이동하는 방법을 보여줍니다.

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

이 태그는 창을 여는 이전 코드와 같은 효과를 갖습니다.

참고

탐색에 대한 자세한 내용은 탐색 개요를 참조하세요.

매개 변수 없는 생성자가 아닌 생성자를 사용하여 이벤트를 인스턴스화하거나, 표시하기 전에 해당 속성을 설정하거나 해당 이벤트를 등록해야 하거나, 애플리케이션이 시작될 때 제공된 모든 명령줄 인수를 처리해야 하는 경우 Startup 이벤트를 처리하여 Window를 열어야 합니다.

명령줄 인수 처리

Windows에서는 명령 프롬프트나 바탕 화면에서 독립 실행형 애플리케이션을 시작할 수 있습니다. 두 경우 모두 명령줄 인수를 애플리케이션으로 전달할 수 있습니다. 다음 예제에서는 단일 명령줄 인수 "/StartMinimized"를 사용하여 시작되는 애플리케이션을 보여 줍니다.

wpfapplication.exe /StartMinimized

애플리케이션이 초기화되는 중에 WPF는 StartupEventArgs 매개 변수의 Args 속성을 통해 운영 체제에서 명령줄 인수를 검색하여 Startup 이벤트 처리기로 전달합니다. 다음과 같은 코드를 사용하여 명령줄 인수를 검색하고 저장할 수 있습니다.

<Application
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App"
  Startup="App_Startup" />
using System.Windows;

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();
        }
    }
}

Imports System.Windows

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

코드에서는 Startup을 처리하여 /StartMinimized 명령줄 인수가 제공되었는지 확인합니다. 인수가 제공된 경우 WindowStateMinimized인 주 창을 엽니다. WindowState 속성은 프로그래밍 방식으로 설정되어야 하므로 기본 Window는 코드에서 명시적으로 열려야 합니다.

XBAP는 ClickOnce 배포를 사용하여 시작되기 때문에 명령줄 인수를 검색하고 처리할 수 없습니다(WPF 애플리케이션 배포 참조). 그러나 XBAP를 시작하는 데 사용되는 URL에서 쿼리 문자열 매개 변수를 검색하고 처리할 수 있습니다.

애플리케이션 활성화 및 비활성화

Windows에서는 사용자가 애플리케이션 간에 전환할 수가 있습니다. 가장 일반적인 방법은 ALT+TAB 키 조합을 사용하는 것입니다. 애플리케이션에 사용자가 선택할 수 있는 Window가 표시되어 있는 경우에만 애플리케이션을 전환할 수 있습니다. 현재 선택된 Window활성 창(전경 창이라고도 함)이며 사용자 입력을 받는 Window입니다. 활성 창이 있는 애플리케이션을 활성 애플리케이션(또는 전경 애플리케이션)이라고 합니다. 다음과 같은 경우에 애플리케이션이 활성 애플리케이션이 됩니다.

  • 애플리케이션이 시작되고 Window를 표시합니다.

  • 사용자가 애플리케이션에서 Window를 선택하여 다른 애플리케이션에서 전환합니다.

Application.Activated 이벤트를 처리하면 애플리케이션이 활성화되는 시점을 감지할 수 있습니다.

마찬가지로 다음과 같은 경우에는 애플리케이션이 비활성화됩니다.

  • 사용자가 현재 애플리케이션에서 다른 애플리케이션으로 전환하는 경우

  • 애플리케이션이 종료되는 경우

Application.Deactivated 이벤트를 처리하면 애플리케이션이 비활성화되는 시점을 감지할 수 있습니다.

다음 코드는 ActivatedDeactivated 이벤트를 처리하여 애플리케이션이 활성화되었는지 확인하는 방법을 보여줍니다.

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

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;
        }
    }
}

Imports System.Windows

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

Window도 활성화 및 비활성화할 수 있습니다. 자세한 내용은 Window.ActivatedWindow.Deactivated를 참조하세요.

참고

XBAP는 Application.ActivatedApplication.Deactivated가 발생하지 않습니다.

애플리케이션 종료

다음과 같은 이유로 애플리케이션이 종료되면 애플리케이션 수명이 끝납니다.

  • 사용자가 모든 Window를 닫습니다.

  • 사용자가 기본 Window를 닫습니다.

  • 사용자가 로그오프하거나 종료하여 Windows 세션을 종료합니다.

  • 애플리케이션별 조건이 충족된 경우

애플리케이션 종료를 쉽게 관리할 수 있도록 Application에서는 Shutdown 메서드, ShutdownMode 속성과 SessionEndingExit 이벤트를 제공합니다.

참고

ShutdownUIPermission이 있는 애플리케이션에서만 호출할 수 있습니다. 독립 실행형 WPF 애플리케이션에는 항상 이 권한이 있습니다. 하지만 인터넷 영역의 부분 신뢰 보안 샌드박스에서 실행되는 XBAP에는 이 권한이 없습니다.

종료 모드

대부분의 애플리케이션은 모든 창을 닫거나 주 창을 닫으면 종료됩니다. 하지만 다른 애플리케이션과 관련된 조건이 특정 애플리케이션의 종료 시점을 결정하는 경우가 있습니다. 다음 ShutdownMode 열거형 값 중 하나로 ShutdownMode를 설정하여 애플리케이션이 종료되는 조건을 지정할 수 있습니다.

ShutdownMode의 기본값은 사용자가 애플리케이션의 마지막 창을 닫으면 애플리케이션이 자동으로 종료되는 OnLastWindowClose입니다. 하지만 주 창이 닫힐 때 애플리케이션을 종료해야 하는 경우 ShutdownModeOnMainWindowClose로 설정하면 WPF에서 자동으로 이를 수행합니다. 다음 예제에서 이를 확인할 수 있습니다.

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

애플리케이션별 종료 조건이 있는 경우ShutdownModeOnExplicitShutdown으로 설정합니다. 이 경우 Shutdown 메서드를 호출하여 명시적으로 애플리케이션을 종료하는 것은 사용자의 책임입니다. 그렇지 않으면 모든 창을 닫은 경우에도 애플리케이션이 계속 실행됩니다. ShutdownModeOnLastWindowClose 또는 OnMainWindowClose인 경우에는 Shutdown이 암시적으로 호출됩니다.

참고

ShutdownMode는 XBAP에서 설정할 수 있지만 이 설정은 무시됩니다. 브라우저에서 다른 위치로 이동하거나 XBAP를 호스트하는 브라우저가 닫히면 XBAP가 항상 종료됩니다. 자세한 내용은 탐색 개요를 참조하세요.

세션 종료

ShutdownMode 속성으로 설명되는 종료 조건은 애플리케이션과 관련이 있습니다. 하지만 외부 조건에 따라 애플리케이션이 종료되는 경우도 있습니다. 가장 일반적인 외부 조건은 다음과 같은 작업으로 사용자가 Windows 세션을 종료하는 경우에 발생합니다.

  • 로그오프

  • 종료

  • 다시 시작

  • 최대 절전 모드

Windows 세션이 종료되는 시점을 감지하려면 다음 예제처럼 SessionEnding 이벤트를 처리하면 됩니다.

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

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;
            }
        }
    }
}

Imports System.Windows

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

이 예제의 코드는 ReasonSessionEnding 속성을 검사하여 Windows 세션이 종료되는 방식을 결정합니다. 또한 이 값을 사용하여 사용자에게 확인 메시지를 표시합니다. 사용자가 세션이 종료되기를 원하지 않는 경우에는 코드에서 Canceltrue로 설정하여 Windows 세션이 종료되지 않게 합니다.

참고

SessionEnding은 XBAP에 대해 발생하지 않습니다.

종료

애플리케이션이 종료될 때 애플리케이션 상태 유지와 같은 몇 가지 최종 처리를 수행해야 할 경우가 있습니다. 이러한 경우 다음 예제의 App_Exit 이벤트 처리기와 마찬가지 방법으로 Exit 이벤트를 처리할 수 있습니다. App.xaml 파일에서 이벤트 처리기로 정의됩니다. 해당 구현은 App.xaml.csApplication.xaml.vb 파일에서 강조 표시됩니다.

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App"
    StartupUri="MainWindow.xaml" 
    Startup="App_Startup" 
    Exit="App_Exit">
    <Application.Resources>
        <SolidColorBrush x:Key="ApplicationScopeResource" Color="White"></SolidColorBrush>
    </Application.Resources>
</Application>
using System.Windows;
using System.IO;
using System.IO.IsolatedStorage;

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

        public App()
        {
            // Initialize application-scope property
            this.Properties["NumberOfAppSessions"] = 0;
        }

        private void App_Startup(object sender, StartupEventArgs e)
        {
            // Restore application-scope property from isolated storage
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();
            try
            {
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filename, FileMode.Open, storage))
                using (StreamReader reader = new StreamReader(stream))
                {
                    // Restore each application-scope property individually
                    while (!reader.EndOfStream)
                    {
                        string[] keyValue = reader.ReadLine().Split(new char[] {','});
                        this.Properties[keyValue[0]] = keyValue[1];
                    }
                }
            }
            catch (FileNotFoundException ex)
            {
                // Handle when file is not found in isolated storage:
                // * When the first application session
                // * When file has been deleted
            }
        }

        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]);
                }
            }
        }
    }
}
Imports System.IO
Imports System.IO.IsolatedStorage

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

        Public Sub New()
            ' Initialize application-scope property
            Me.Properties("NumberOfAppSessions") = 0
        End Sub

        Private Sub App_Startup(ByVal sender As Object, ByVal e As StartupEventArgs)
            ' Restore application-scope property from isolated storage
            Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForDomain()
            Try
                Using stream As New IsolatedStorageFileStream(filename, FileMode.Open, storage)
                Using reader As New StreamReader(stream)
                    ' Restore each application-scope property individually
                    Do While Not reader.EndOfStream
                        Dim keyValue() As String = reader.ReadLine().Split(New Char() {","c})
                        Me.Properties(keyValue(0)) = keyValue(1)
                    Loop
                End Using
                End Using
            Catch ex As FileNotFoundException
                ' Handle when file is not found in isolated storage:
                ' * When the first application session
                ' * When file has been deleted
            End Try
        End Sub

        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

전체 예제는 애플리케이션 세션 간의 애플리케이션 범위 속성 유지 및 복원을 참조하세요.

Exit는 독립 실행형 애플리케이션과 XBAP 모두에서 처리할 수 있습니다. XBAP에서는 다음과 같은 경우에 Exit가 발생합니다.

  • XBAP가 다른 위치로 이동하는 경우

  • Internet Explorer에서 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 이벤트 처리기는 ApplicationExitCode 속성이 있는 종료 코드에 대한 액세스를 제공하는 ExitEventArgs를 전달합니다. 자세한 내용은 Exit를 참조하세요.

참고

독립 실행형 애플리케이션 및 XBAP 모두에서 종료 코드를 설정할 수 있습니다. 하지만 XBAP의 경우 종료 코드 값이 무시됩니다.

처리되지 않은 예외

원하지 않는 예외를 throw하는 경우와 같이 애플리케이션이 비정상적인 상황에서 종료되는 경우가 있습니다. 이런 경우에는 애플리케이션에 예외를 검색하고 처리할 코드가 없을 수 있습니다. 이런 형식의 예외가 처리되지 않은 예외이며, 애플리케이션이 닫히기 전에 다음 그림에 표시된 것과 비슷한 알림으로 표시됩니다.

처리되지 않은 예외 알림을 보여주는 스크린샷.

사용자 환경의 관점에서는 애플리케이션에서 다음과 같은 작업의 일부 또는 전부를 수행하여 이러한 기본 동작을 방지하는 것이 바람직합니다.

  • 사용자에게 친숙한 정보 표시

  • 애플리케이션을 실행 상태로 유지

  • Windows 이벤트 로그에 개발자에게 친숙한 세부적인 예외 정보 기록

이러한 지원을 구현하는 것은 처리되지 않은 예외, 다시 말해 DispatcherUnhandledException 이벤트가 발생하는 원인을 검색할 수 있는지에 따라 달라집니다.

<Application
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.App"
  StartupUri="MainWindow.xaml"
  DispatcherUnhandledException="App_DispatcherUnhandledException" />
using System.Windows;
using System.Windows.Threading;

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;
        }
    }
}
Imports System.Windows
Imports System.Windows.Threading

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

DispatcherUnhandledException 이벤트 처리기는 예외 자체(DispatcherUnhandledExceptionEventArgs.Exception)를 포함하여 처리되지 않은 예외와 관련된 컨텍스트 정보를 포함하는 DispatcherUnhandledExceptionEventArgs 매개 변수를 전달합니다. 이 정보를 사용하여 예외를 처리하는 방법을 결정할 수 있습니다.

DispatcherUnhandledException을 처리할 때는 DispatcherUnhandledExceptionEventArgs.Handled 속성을 true로 설정해야 합니다. 그러지 않으면 WPF에서 계속해서 예외가 처리되지 않은 것으로 간주하고 이전에 설명한 기본 동작으로 돌아갑니다. 처리되지 않은 예외가 발생하고 DispatcherUnhandledException 이벤트가 처리되지 않거나, 이벤트가 처리되지만 Handledfalse로 설정된 경우 애플리케이션이 즉시 종료됩니다. 뿐만 아니라 다른 Application 이벤트가 발생하지 않습니다. 따라서 애플리케이션에 애플리케이션이 종료되기 전에 실행되어야 하는 코드가 있는 경우 DispatcherUnhandledException을 처리해야 합니다.

처리되지 않은 예외의 결과로 애플리케이션이 종료될 수는 있지만 애플리케이션은 대개 다음 섹션에서 설명하는 것처럼 사용자 요청에 대한 응답으로 종료됩니다.

애플리케이션 수명 이벤트

독립 실행형 애플리케이션과 XBAP는 수명이 동일하지 않습니다. 다음 그림에서는 독립 실행형 애플리케이션 수명에서의 주요 이벤트와 이러한 이벤트가 발생하는 순서를 보여 줍니다.

독립 실행형 애플리케이션 - 애플리케이션 개체 이벤트

마찬가지로 다음 그림에서는 XBAP 수명에서의 주요 이벤트와 이러한 이벤트가 발생하는 순서를 보여줍니다.

XBAP - 애플리케이션 개체 이벤트

참고 항목