개체 수명 이벤트(WPF .NET)

수명 동안 Microsoft .NET 관리 코드의 모든 개체는 만들기, 사용소멸 단계를 거칩니다. WPF(Windows Presentation Foundation)는 수명 이벤트를 발생시켜 개체에서 발생하는 이러한 단계에 대한 알림을 제공합니다. WPF 프레임워크 수준 요소(시각적 개체)의 경우 WPF는 Initialized, LoadedUnloaded 수명 이벤트를 구현합니다. 개발자는 이러한 수명 이벤트를 요소를 포함하는 코드 숨김 작업의 연결로서 사용할 수 있습니다. 이 문서에서는 시각적 개체의 수명 이벤트를 설명한 다음 창 요소, 탐색 호스트 또는 애플리케이션 개체에 특별히 적용되는 다른 수명 이벤트를 소개합니다.

중요

.NET 7 및 .NET 6에 관한 데스크톱 가이드 설명서는 제작 중입니다.

사전 요구 사항

이 문서에서는 WPF 요소 레이아웃을 트리로 개념화하는 방법과 라우트된 이벤트 개요를 읽은 방법에 대한 기본 지식을 가정합니다. XAML(Extensible Application Markup Language)에 익숙하고 WPF 애플리케이션을 작성하는 방법을 알고 있으면 이 문서의 예제를 따라 하는 데 도움이 됩니다.

시각적 개체에 대한 수명 이벤트

WPF 프레임워크 수준 요소는 FrameworkElement 또는 FrameworkContentElement에서 파생됩니다. Initialized, LoadedUnloaded 수명 이벤트는 모든 WPF 프레임워크 수준 요소에 공통적으로 적용됩니다. 다음 예제에서는 주로 XAML에서 구현되는 요소 트리를 보여줍니다. XAML은 각각 XAML 특성 구문을 사용하여 Initialized, LoadedUnloaded 수명 이벤트 처리기를 연결하는 중첩된 요소를 포함하는 부모 Canvas 요소를 정의합니다.

<Canvas x:Name="canvas">
    <StackPanel x:Name="outerStackPanel" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
        <custom:ComponentWrapper x:Name="componentWrapper" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler">
            <TextBox Name="textBox1" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
            <TextBox Name="textBox2" Initialized="InitHandler" Loaded="LoadHandler" Unloaded="UnloadHandler" />
        </custom:ComponentWrapper>
    </StackPanel>
    <Button Content="Remove canvas child elements" Click="Button_Click"/>
</Canvas>

XAML 요소 중 하나는 코드 숨김에서 수명 이벤트 처리기를 할당하는 기본 클래스에서 파생되는 사용자 지정 컨트롤입니다.

public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    // Handler for the Initialized lifetime event (attached in XAML).
    private void InitHandler(object sender, System.EventArgs e) => 
        Debug.WriteLine($"Initialized event on {((FrameworkElement)sender).Name}.");

    // Handler for the Loaded lifetime event (attached in XAML).
    private void LoadHandler(object sender, RoutedEventArgs e) => 
        Debug.WriteLine($"Loaded event on {((FrameworkElement)sender).Name}.");

    // Handler for the Unloaded lifetime event (attached in XAML).
    private void UnloadHandler(object sender, RoutedEventArgs e) =>
        Debug.WriteLine($"Unloaded event on {((FrameworkElement)sender).Name}.");

    // Remove nested controls.
    private void Button_Click(object sender, RoutedEventArgs e) => 
        canvas.Children.Clear();
}

// Custom control.
public class ComponentWrapper : ComponentWrapperBase { }

// Custom base control.
public class ComponentWrapperBase : StackPanel
{
    public ComponentWrapperBase()
    {
        // Assign handler for the Initialized lifetime event (attached in code-behind).
        Initialized += (object sender, System.EventArgs e) => 
            Debug.WriteLine($"Initialized event on componentWrapperBase.");

        // Assign handler for the Loaded lifetime event (attached in code-behind).
        Loaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Loaded event on componentWrapperBase.");

        // Assign handler for the Unloaded lifetime event (attached in code-behind).
        Unloaded += (object sender, RoutedEventArgs e) => 
            Debug.WriteLine($"Unloaded event on componentWrapperBase.");
    }
}

/* Output:
Initialized event on textBox1.
Initialized event on textBox2.
Initialized event on componentWrapperBase.
Initialized event on componentWrapper.
Initialized event on outerStackPanel.

Loaded event on outerStackPanel.
Loaded event on componentWrapperBase.
Loaded event on componentWrapper.
Loaded event on textBox1.
Loaded event on textBox2.

Unloaded event on outerStackPanel.
Unloaded event on componentWrapperBase.
Unloaded event on componentWrapper.
Unloaded event on textBox1.
Unloaded event on textBox2.
*/
Partial Public Class MainWindow
    Inherits Window

    Public Sub New()
        InitializeComponent()
    End Sub

    ' Handler for the Initialized lifetime event (attached in XAML).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine($"Initialized event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in XAML).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Loaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in XAML).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine($"Unloaded event on {CType(sender, FrameworkElement).Name}.")
    End Sub

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        ' Remove nested controls.
        canvas.Children.Clear()
    End Sub
End Class

' Custom control.
Public Class ComponentWrapper
    Inherits ComponentWrapperBase
End Class

' Custom base control.
Public Class ComponentWrapperBase
    Inherits StackPanel

    Public Sub New()
        ' Attach handlers for the lifetime events.
        AddHandler Initialized, AddressOf InitHandler
        AddHandler Loaded, AddressOf LoadHandler
        AddHandler Unloaded, AddressOf UnloadHandler
    End Sub

    ' Handler for the Initialized lifetime event (attached in code-behind).
    Private Sub InitHandler(sender As Object, e As EventArgs)
        Debug.WriteLine("Initialized event on componentWrapperBase.")
    End Sub

    ' Handler for the Loaded lifetime event (attached in code-behind).
    Private Sub LoadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Loaded event on componentWrapperBase.")
    End Sub

    ' Handler for the Unloaded lifetime event (attached in code-behind).
    Private Sub UnloadHandler(sender As Object, e As RoutedEventArgs)
        Debug.WriteLine("Unloaded event on componentWrapperBase.")
    End Sub
End Class

'Output:
'Initialized event on textBox1.
'Initialized event on textBox2.
'Initialized event on componentWrapperBase.
'Initialized event on componentWrapper.
'Initialized event on outerStackPanel.

'Loaded event on outerStackPanel.
'Loaded event on componentWrapperBase.
'Loaded event on componentWrapper.
'Loaded event on textBox1.
'Loaded event on textBox2.

'Unloaded event on outerStackPanel.
'Unloaded event on componentWrapperBase.
'Unloaded event on componentWrapper.
'Unloaded event on textBox1.
'Unloaded event on textBox2.

프로그램 출력은 각 트리 개체에서 Initialized, LoadedUnloaded 수명 이벤트의 호출 순서를 보여줍니다. 이러한 이벤트는 각 트리 개체에서 발생하는 순서대로 다음 섹션에서 설명합니다.

초기화된 수명 이벤트

WPF 이벤트 시스템은 요소에서 Initialized 이벤트를 발생시킵니다.

  • 요소의 속성이 설정된 경우.
  • 개체가 생성자에 대한 호출을 통해 초기화되는 것과 거의 같은 시간입니다.

Panel.Children과(와) 같은 일부 요소 속성에는 자식 요소가 포함될 수 있습니다. 부모 요소는 자식 요소가 초기화될 때까지 초기화를 보고할 수 없습니다. 따라서 속성 값은 요소 트리에서 가장 깊이 중첩된 요소부터 시작하여 애플리케이션 루트까지 이어지는 부모 요소로 설정됩니다. Initialized 이벤트는 요소의 속성이 설정될 때 발생하므로 해당 이벤트는 태그에 정의된 대로 가장 깊이 중첩된 요소에서 먼저 호출되고, 그 다음에는 애플리케이션 루트까지 연속 부모 요소가 호출됩니다. 코드 숨김에서 개체를 동적으로 만들면 초기화 시퀀스가 부족할 수 있습니다.

WPF 이벤트 시스템은 요소 트리의 모든 요소가 초기화될 때까지 기다리지 않고 요소에서 Initialized 이벤트를 발생합니다. 따라서 모든 요소에 대한 Initialized 이벤트 처리기를 작성할 때 논리 또는 시각적 트리의 주변 요소, 특히 부모 요소가 만들어지지 않았을 수 있습니다. 또는 멤버 변수 및 데이터 바인딩이 초기화되지 않을 수 있습니다.

참고

요소에서 Initialized 이벤트가 발생하면 동적 리소스 또는 바인딩과 같은 요소의 식 사용량은 평가되지 않습니다.

로드된 수명 이벤트

WPF 이벤트 시스템은 요소에서 Loaded 이벤트를 발생시킵니다.

  • 요소를 포함하는 논리 트리가 완료되고 프레젠테이션 원본에 연결된 경우. 프레젠테이션 원본은 HWND(창 핸들) 및 렌더링 화면을 제공합니다.
  • 다른 속성 또는 직접 정의된 데이터 원본과 같은 로컬 원본에 대한 데이터 바인딩이 완료되는 경우.
  • 레이아웃 시스템에서 렌더링에 필요한 모든 값을 계산한 후.
  • 최종 렌더링 전.

Loaded 이벤트는 논리 트리 내의 모든 요소가 로드될 때까지 요소 트리의 모든 요소에서 발생하지 않습니다. WPF 이벤트 시스템은 먼저 요소 트리의 루트 요소에서 Loaded 이벤트를 발생시킨 다음, 각 연속 자식 요소에서 가장 깊이 중첩된 요소로 내립니다. 이 이벤트는 터널링 라우트된 이벤트와 유사할 수 있지만 Loaded 이벤트는 이벤트 데이터를 한 요소에서 다른 요소로 전달하지 않으므로 이벤트를 처리됨으로 표시해도 아무런 효과가 없습니다.

참고

WPF 이벤트 시스템은 Loaded 이벤트 전에 비동기 데이터 바인딩이 완료된 것을 보장할 수 없습니다. 비동기 데이터 바인딩은 외부 또는 동적 원본에 바인딩됩니다.

언로드된 수명 이벤트

WPF 이벤트 시스템은 요소에서 Unloaded 이벤트를 발생시킵니다.

  • 프레젠테이션 원본 제거 시 또는
  • 시각적 개체 부모 제거 시.

WPF 이벤트 시스템은 먼저 요소 트리의 루트 요소에서 Unloaded 이벤트를 발생시킨 다음, 각 연속 자식 요소에서 가장 깊이 중첩된 요소로 내립니다. 이 이벤트는 터널링 라우트된 이벤트와 유사할 수 있지만 Unloaded 이벤트는 이벤트 데이터를 요소끼리 전파하지 않으므로 이벤트를 처리됨으로 표시해도 아무런 효과가 없습니다.

Unloaded 이벤트가 요소에서 발생하는 경우 부모 요소이거나 논리 또는 시각적 개체 트리의 상위 요소가 이미 설정되지 않았을 수 있습니다. 설정되지 않았다는 것은 요소의 데이터 바인딩, 리소스 참조 및 스타일이 더 이상 정상 또는 마지막으로 알려진 런타임 값으로 설정되지 않음을 의미합니다.

다른 수명 이벤트

수명 이벤트 관점에서 WPF 개체에는 일반적인 요소, 창 요소, 탐색 호스트 및 애플리케이션 개체 등 네 가지 기본 유형이 있습니다. Initialized, LoadedUnloaded 수명 이벤트는 모든 프레임워크 수준 요소에 적용됩니다. 다른 수명 이벤트는 특히 창 요소, 탐색 호스트 또는 애플리케이션 개체에 적용됩니다. 이러한 다른 수명 이벤트에 대한 자세한 내용은 다음을 참조하세요.

참고 항목