WinUI 3 애플리케이션의 이상 오류 처리

WinUI 3 앱은 디버그 모드에서는 정상적으로 실행되지만 릴리스 빌드로 제작하면 충돌이 발생합니다. 발생한 오류 내용은 아래와 같습니다.

일반 개발 과정에서 이런 황당한 문제를 마주하는 일은 거의 없습니다. WinUI 3는 대부분 내부 런타임 예외를 반환하기 때문에 예외 스택에서 유용한 단서를 찾기 매우 어렵습니다.

여러 차례 제거 테스트를 진행한 결과, 페이지 내 ViewModel을 초기화할 때 발생하는 널 참조 오류가 앱 충돌의 원인임을 확인했습니다. 프로젝트 구조는 다음과 같습니다. 사이드바 탐색 메뉴가 있는 메인 창에서 메뉴 항목을 클릭하면 오른쪽 메인 콘텐츠 영역에 대상 페이지가 로드됩니다. 메인 창에 사용한 XAML 코드 조각은 아래와 같습니다.

<TabView Name="tabView" IsAddTabButtonVisible="False" Margin="10" VerticalAlignment="Stretch" TabCloseRequested="TabView_TabCloseRequested">
    <TabViewItem x:Uid="tabConsonant" Name="tvHome">
    </TabViewItem>
</TabView>Code language: HTML, XML (xml)

이 TabView 컨트롤은 오른쪽 영역에 콘텐츠 페이지를 표시하는 역할을 합니다. 백엔드 코드에서 대상 페이지 인스턴스를 tvHome에 할당하고 있습니다.

private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
    tvHome.Content = new ConsonantsPage();
}Code language: JavaScript (javascript)

추가 디버깅을 통해 충돌이 대상 페이지 내의 this.DataContext = vm; 코드 라인에서 정확히 발생함을 확인했습니다.

그 후 DataContext와 데이터 바인딩을 전혀 사용하지 않은 깨끗한 페이지를 테스트했는데, 해당 페이지는 오류 없이 정상적으로 로드되었습니다. 이로써 근본 원인이 XAML 바인딩 로직과 관련됨을 확실히 알 수 있습니다. 기존 표준 MVVM 바인딩 방식을 포기하고, 임시 방편으로 코드 비하인드에서 직접 프로그래밍 방식으로 UI 요소를 생성하는 방식으로 전환했습니다.

최종 적용된 정상 해결 방안:

모든 컨트롤 생성 및 값 바인딩 작업을 C# 백엔드 코드로 전부 처리합니다.

 public TonePage()
        {
            InitializeComponent();
            Loaded += Page_Loaded;
        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            var toneData = ThaiAlphabetSource.Tones;
            FillToneGrid(gvToneList, toneData);
        }

        private void FillToneGrid(GridView grid, List<ToneInfo> source)
        {
            foreach (var item in source)
            {
                Button btnRoot = new Button
                {
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    VerticalContentAlignment = VerticalAlignment.Center,
                    Tag = item.Audio
                };
                btnRoot.Click += PlayClick;

                StackPanel sp = new StackPanel
                {
                    Width = 240,
                    Orientation = Orientation.Vertical,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center
                };

                TextBlock tbTitle = new TextBlock
                {
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    FontSize = 50,
                    Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0x01, 0xA0, 0xC7)),
                    Text = item.Letter_Title
                };
                TextBlock tbName = new TextBlock
                {
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    FontSize = 30,
                    Text = item.Letter_Name
                };
                TextBlock tbScript = new TextBlock
                {
                    HorizontalContentAlignment = HorizontalAlignment.Center,
                    FontSize = 30,
                    Text = item.Letter_Script
                };

                sp.Children.Add(tbTitle);
                sp.Children.Add(tbName);
                sp.Children.Add(tbScript);
                btnRoot.Content = sp;

                grid.Items.Add(btnRoot);
            }
        }Code language: PHP (php)

근본적인 내부 오류를 자세히 파고들어 확인하지는 않았지만, Command="{Binding PlayCommand}" 와 같은 명령어 바인딩 구문이 문제의 원인일 것으로 추측합니다. 또 다른 테스트 케이스가 이 추측을 뒷받침합니다. 명령어 바인딩 없이 단순 속성 바인딩만 사용한 페이지는 아래 예시처럼 릴리스 환경에서도 원활하게 작동합니다.

<Button Content="{Binding}" Grid.Row="0" Grid.Column="1" BorderBrush="#ccc" Foreground="Black" FontSize="50" Height="100" Width="130" Click="Button_Click"/>Code language: HTML, XML (xml)

이 작성 방식은 릴리스 구성에서 정상적으로 동작합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다