c# wpf Application.MainWindow와 컨스트럭터의 작동 순서

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    nint handle1 = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    nint handle2 = new WindowInteropHelper(this).Handle;

    LogTextBlock.Text = $"{handle1} {handle2}";
}

위 코드는 wpf에서 매인 윈도우의 핸들을 구한다. Application.Current.MainWindow와 this는 같으니 같은 핸들들을 출력한다.

Window1 Window1 = new();

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    nint handle1 = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    nint handle2 = new WindowInteropHelper(this).Handle;

    LogTextBlock.Text = $"{handle1} {handle2}";
}

핸들을 구하는 익스프레션과 관계 없는 Window1 Window1 = new();를 추가하면 엉뚱한 결과가 나온다. handle1이 0이다. 이 현상은 로그인 창을 만들 때 문제가 될 수 있다.

필드 초기화는 컨스트럭터 실행의 일부다. 매인 윈도우의 컨스트럭터가 시작하면 Window1 Window1 = new();가 작동하여 Window1의 인스턴스를 만든다. 그 뒤에야 매인 윈도우의 컨스트럭터가 끝난다. Window1은 매인 윈도우보다 먼저 생기지만 핸들은 아직 없다.

The first Window that is instantiated within a WPF application is automatically set by Application as the main application window.
How to get or set the main application window

Application.Current.MainWindow는 그 이름과 달리 매인 윈도우를 프라퍼티로 할당하지 않고 처음 생긴 윈도우를 할당한다. 따라서 0을 반환한다.

this는 다르다. Application.MainWindow는 프라퍼티지만 this는 클래스 인스턴스이므로 틀리게 할당하고 말고 할 여지가 없다.

nint handle1 = new WindowInteropHelper(Application.Current.MainWindow).EnsureHandle();

If the native window has not yet been created, this method creates the native window, sets the Handle property, and returns the HWND.
WindowInteropHelper.EnsureHandle Method

위 메떠드를 이용하면 위 문제를 피할 수 있다. 그러나 이 방법보다는 컨스트럭터의 작동 원리를 알고 윈도우들이 만들어지는 순서를 취지에 맞게 구현하는 게 근본적인 방법이다. 자식 윈도우를 매인 윈도우보다 먼저 만드는 경우는 일반적이지 않다. 자식 윈도우는 필드 선언만 하고 초기화는 자식 윈도우를 열 때 하는 게 좋다.