rksoftware

Visual Studio とか C# とかが好きです

XAML Islands で InitializeForCurrentThread メソッドが必要なパターン

以前に XAML Islands で UWP のコントロールを生成する場合、その前に

global::Windows.UI.Xaml.Hosting.WindowsXamlManager.InitializeForCurrentThread();

の一文が必要らしいけれど、実際書かなくても大丈夫だったと書きました。
今回この一文を書く必要がある場合と書かなくて良い場合の話です。

■ 結論

  • WindowsXamlHost コントロールを生成する前に UWP コントロールを生成する場合に必要。
  • 既に WindowsXamlHost コントロールを生成しているスレッドでは不要。

です。
言葉だけでは分かりづらいと思いますので、コードで見ていきましょう。

■ エラーとなる例

次のコードは実行時にエラーになります。
WindowsXamlHost を生成する前に UWP のコントロール (ProgressRing) を生成しようとするためです。

using System.Windows;

namespace WpfApp1
{
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            // UWP のコントロールを生成
            var progressRing = new Windows.UI.Xaml.Controls.ProgressRing
            {
                Height = 300,
                Width = 200,
                IsActive = true,
            };

            // WindowsXamlHost を生成
            var host = new Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost
            {
                Height = 300,
                Width = 200,
            };

            // 画面に配置
            host.Child = progressRing;
            this.AddChild(host);
        }
    }
}

■ InitializeForCurrentThread メソッドでエラーを解消

次のように UWP のコントロールを生成する前に InitializeForCurrentThread メソッドを呼ぶとエラーにならず動作します。

using System.Windows;

namespace WpfApp1
{
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            // おまじない
            global::Windows.UI.Xaml.Hosting.WindowsXamlManager.InitializeForCurrentThread();

            // UWP のコントロールを生成
            var progressRing = new Windows.UI.Xaml.Controls.ProgressRing
            {
                Height = 300,
                Width = 200,
                IsActive = true,
            };

            // WindowsXamlHost を生成
            var host = new Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost
            {
                Height = 300,
                Width = 200,
            };

            // 画面に配置
            host.Child = progressRing;
            this.AddChild(host);
        }
    }
}

■ コントロール生成順を変更してエラーを解消

次の例もエラーにならず実行できます。
エラーの条件は、WindowsXamlHost を生成する前に UWP のコントロールを生成する、言い換えると「先に WindowsXamlHost を生成していれば OK」です。前述のエラーとなるコードの中のコントロールの生成順を入れ替え最初に WindowsXamlHost を生成するようにすればエラーとならずに動作します。

using System.Windows;

namespace WpfApp1
{
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            // WindowsXamlHost を生成
            var host = new Microsoft.Toolkit.Wpf.UI.XamlHost.WindowsXamlHost
            {
                Height = 300,
                Width = 200,
            };

            // UWP のコントロールを生成
            var progressRing = new Windows.UI.Xaml.Controls.ProgressRing
            {
                Height = 300,
                Width = 200,
                IsActive = true,
            };

            // 画面に配置
            host.Child = progressRing;
            this.AddChild(host);
        }
    }
}