rksoftware

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

もう一つの XAML 諸島のコントロールの設定方法 (WPF編)

先日、WPF アプリケーションでの XAML Islands を試す記事を書きました。

しかしこの方法だと、使う UWP のエレメント名を文字列で指定せねばならず、プロパティも ChildChanged イベントでの設定になます。また階層化された複数のエレメントを配置するなどもできません。

■ コードでコントロールを生成する

最近このパターンばかりですが、コードで全てを設定すれば解決します。
次のように使いたいエレメントをインスタンス化して、WindowsXamlHost の Child プロパティに設定しても使えるようです。

using System;
using System.Windows;

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

            {
                var progressRing = new Windows.UI.Xaml.Controls.ProgressRing
                {
                    IsActive = true,
                    Width = 300,
                    Height = 200,
                };
                windowsXamlHost1.Child = progressRing;
            }

            {
                var inkCanvas = new Windows.UI.Xaml.Controls.InkCanvas
                {
                    Width = 300,
                    Height = 200,
                };
                inkCanvas.InkPresenter.InputDeviceTypes =
                    Windows.UI.Core.CoreInputDeviceTypes.Mouse
                    | Windows.UI.Core.CoreInputDeviceTypes.Pen;
                windowsXamlHost2.Child = inkCanvas;
            }
        }
    }
}

f:id:rksoftware:20190106151255j:plain

■ 階層化

エレメントを階層する場合もこの様に。

using System;
using System.Windows;

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

            var grid = new Windows.UI.Xaml.Controls.Grid();

            {
                var progressRing = new Windows.UI.Xaml.Controls.ProgressRing
                {
                    IsActive = true,
                    Width = 300,
                    Height = 200,
                };

                grid.Children.Add(progressRing);
            }

            {
                var inkCanvas = new Windows.UI.Xaml.Controls.InkCanvas
                {
                    Width = 300,
                    Height = 200,
                };
                inkCanvas.InkPresenter.InputDeviceTypes =
                    Windows.UI.Core.CoreInputDeviceTypes.Mouse
                    | Windows.UI.Core.CoreInputDeviceTypes.Pen;

                grid.Children.Add(inkCanvas);
            }

            windowsXamlHost1.Child = grid;
        }
    }
}

この例では、ProgressRing と InkCanvas を Grid の子要素として重ねて表示されるようにしています。 f:id:rksoftware:20190106151312j:plain

注意

私の環境では行わなくても動作しましたが、これらの方法はドキュメントによると次の一文が最初に必要だと書いてあるような気がします。

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

この WindowsXamlManager クラスの InitializeForCurrentThread メソッドですが、Windows.UI.Xaml.Hosting.HostingContract (C:\Program Files (x86)\Windows Kits\10\References\<バージョン>\Windows.UI.Xaml.Hosting.HostingContract\<バージョン>\Windows.UI.Xaml.Hosting.HostingContract.winmd) を参照に追加すると使用できました。

追記

InitializeForCurrentThread が必要になるパターンを確認してみました。