WinUI 3 アプリケーションの異常現象対処

WinUI 3 アプリケーションの異常現象対処

本 WinUI 3 アプリはデバッグモードでは正常に動作しますが、リリースビルドを作成するとクラッシュします。発生したエラーは以下の通りです。

通常の開発でこのような奇妙な不具合に遭遇することはほとんどありません。WinUI 3 は内部ランタイム例外を出力することが多く、例外スタックから有用な手がかりを読み取るのが困難です。

複数回の動作確認と切り分け試験を行った結果、ページ内のViewModel初期化時にNull参照例外が発生し、クラッシュに至ることを突き止めました。プロジェクトの構成は以下の通りです。メインウィンドウにサイドバーのナビゲーションメニューを配置し、メニュー項目をクリックすると右側のコンテンツ領域に対象のページが読み込まれる仕組みです。メインウィンドウで使用している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
                {
                    HorizontalAlignment = HorizontalAlignment.Center,
                    FontSize = 50,
                    Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0x01, 0xA0, 0xC7)),
                    Text = item.Letter_Title
                };
                TextBlock tbName = new TextBlock
                {
                    HorizontalAlignment = HorizontalAlignment.Center,
                    FontSize = 30,
                    Text = item.Letter_Name
                };
                TextBlock tbScript = new TextBlock
                {
                    HorizontalAlignment = 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)

この記述形式はリリース構成で正常に動作します。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です