XAML Islands を使用して、C# WPF アプリで UWP XAML コントロールをホストする

重要

このトピックでは、CommunityToolkit/Microsoft.Toolkit.Win32 GitHub リポジトリの型について使用または言及します。 XAML Islands のサポートに関する重要な情報については、そのリポジトリの XAML Islands に関する通知を参照してください。

このトピックでは、XAML Islands を使用してユニバーサル Windows プラットフォーム (UWP) XAML コントロール (つまり、Windows SDK によって提供されるファーストパーティ コントロール) をホストする C# Windows Presentation Foundation (WPF) アプリ (.NET Core 3.1 がターゲット) を構築する方法について説明します。 これを行うための次の 2 つの方法について説明します。

  • Windows Community Toolkit で利用可能なラップされたコントロールを使用して、UWP の InkCanvas コントロールと InkToolbar コントロールをホストする方法を示します。 ラップされたコントロールでは、便利な UWP XAML コントロールの小さいセットのインターフェイスと機能がラップされています。 ラップされたコントロールを WPF または Windows フォーム プロジェクトのデザイン サーフェイスに直接追加し、デザイナーで他の WPF や Windows フォーム コントロールと同様に使用できます。

  • また、Windows Community Toolkit で利用可能な WindowsXamlHost コントロールを使用して、UWP の CalendarView コントロールをホストする方法についても説明します。 ラップされたコントロールとして使用できるのは少数の UWP XAML コントロールだけであり、他の UWP XAML コントロールをホストするには WindowsXamlHost を使用できます。

WPF アプリで UWP XAML コントロールをホストするプロセスは、Windows フォーム アプリに似ています。

重要

XAML アイランド (ラップされたコントロールまたは WindowsXamlHost) を使用して UWP XAML コントロールをホストすることは、.NET Core 3.x をターゲットとするアプリでのみサポートされています。 XAML Islands は、.NET をターゲットとするアプリ、または .NET Framework のすべてのバージョンをターゲットとするアプリでは、サポートされていません。

WPF または Windows フォーム アプリで UWP XAML コントロールをホストするには、ソリューションに次のコンポーネントを用意することをお勧めします。 この記事では、これらの各コンポーネントを作成する手順について説明します。

  • WPF または Windows フォーム アプリのプロジェクトとソース コード

  • XamlApplication から派生するルート Application クラスが定義されている UWP プロジェクトMicrosoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスは、Windows Community Toolkit で利用できます。 XamlApplication によって派生するアプリケーション クラスは、WPF または Windows フォーム Visual Studio ソリューションの一部である別の UWP アプリ プロジェクトとして定義することをお勧めします。

    注意

    ファーストパーティ UWP XAML コントロールをホストするために、XamlApplication から派生したオブジェクトを WPF または Windows フォーム プロジェクトで使用できるようにすることは、実際には必要ありません。 ただし、カスタム UWP XAML コントロールを検出、ロード、およびホストするためには必要です。 そのため、XAML Islands のすべてのシナリオをサポートするには、常に、XAML Islands を使用するすべてのソリューションで、XamlApplication によって派生したオブジェクトを定義することをお勧めします。

    注意

    XamlApplication によって派生したオブジェクトは、ソリューション内の 1 つのプロジェクトだけで定義されている必要があります。 その 1 つのプロジェクトは、XAML Islands を介して UWP XAML コントロールをホストする他のライブラリおよびプロジェクトを参照する必要があります。

WPF プロジェクトを作成する

次の手順に従って新しい WPF プロジェクトを作成し、XAML Islands をホストするように構成できます。 WPF プロジェクトが既にある場合は、以下の手順とコード例をプロジェクトに合わせて調整してかまいません。

  1. まだ行っていない場合は、最新バージョンの .NET Core 3.1 をインストールします。

  2. Visual Studio で、WPF アプリケーション プロジェクト テンプレートから新しいプロジェクトを作成します。 このトピックの手順やソース コードを編集する必要がないように、プロジェクト名MyWPFApp に設定します。 [フレームワーク].NET Core 3.1* に設定し、[作成] をクリックします。

重要

WPF アプリ (.NET Framework) プロジェクト テンプレートは使用しないようにしてください。

WPF プロジェクトの構成

  1. 以下の手順に従って、パッケージ参照を有効にします。

    1. Visual Studio で、[ツール] > [NuGet パッケージ マネージャー] > [パッケージ マネージャー設定] の順にクリックします。
    2. 右側で [パッケージの管理] > [既定のパッケージ管理形式] 設定を見つけて、[PackageReference] に設定します。
  2. 次の手順を使用して、Microsoft.Toolkit.Wpf.UI.Controls NuGet パッケージをインストールします。

    1. ソリューション エクスプローラーMyWPFApp プロジェクト ノードを右クリックし、[NuGet パッケージの管理] を選択します。

    2. [参照] タブで、検索ボックスに「Microsoft.Toolkit.Wpf.UI.Controls」と入力するか、これを貼り付けます。 最新の安定バージョンを選択し、[インストール] をクリックします。 このパッケージでは、WPF でラップされた UWP XAML コントロールを使用するために必要なものがすべて提供されています (InkCanvasInkToolbarWindowsXamlHost コントロールなど)。

    注意

    Windows フォーム アプリの場合は、代わりに Microsoft.Toolkit.Forms.UI.Controls パッケージを参照してください。

  3. XAML Islands のほとんどのシナリオは、[任意の CPU] を対象とするプロジェクトではサポートされていません。 そのため、特定のアーキテクチャ (x86x64 など) を対象にするには、次の手順を実行します。

    1. ソリューション エクスプローラーでソリューション ノード (プロジェクト ノードではありません) を右クリックし、[プロパティ] を選択します。
    2. 左側の [構成プロパティ] を選択します。
    3. [構成マネージャー] ボタンをクリックします。
    4. [アクティブ ソリューション プラットフォーム] で、 [新規作成] を選択します。
    5. [新しいソリューション プラットフォーム] ダイアログで、[x64] または [x86] を選択して、[OK] をクリックします。
    6. 開いているダイアログ ボックスを閉じます。

UWP アプリ プロジェクトで XamlApplication クラスを定義する

このセクションでは、UWP アプリ プロジェクトをソリューションに追加し、このプロジェクトの既定の App クラスを、Windows Community Toolkit によって提供される Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication クラスから派生するように変更します。 このクラスでは、IXamlMetadataProvider インターフェイスがサポートされています。これにより、アプリの実行時に、アプリケーションの現在のディレクトリにある、アセンブリ内のカスタム UWP XAML コントロールのメタデータを検出して読み込むことができるようになります。 このクラスでは、現在のスレッドの UWP XAML フレームワークも初期化されます。

  1. ソリューション エクスプローラーで、ソリューション ノードを右クリックし、[追加]>[新しいプロジェクト] を選択します。

  2. C# [空のアプリ (ユニバーサル Windows)] プロジェクト テンプレートを選択します。 このトピックの手順やソース コードを編集する必要がないように、プロジェクト名MyUWPApp に設定します。 [ターゲット バージョン][最小バージョン]Windows 10、バージョン 1903 (ビルド 18362)、またはそれ以降に設定します。

    注意

    MyWPFApp のサブフォルダーに MyUWPApp を作成しないようにしてください。 これを行うと、MyWPFApp は、UWP XAML マークアップを WPF XAML であるかのようにビルドしようとします。

  3. MyUWPApp で、Microsoft.Toolkit.Win32.UI.XamlApplication NuGet パッケージ (最新の安定バージョン) をインストールします。 NuGet パッケージのインストール手順については、前のセクションで説明しました。

  4. MyUWPAppApp.xaml ファイルを開き、その内容を次の XAML に置き換えます。

    <xaml:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xaml="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns:local="using:MyUWPApp">
    </xaml:XamlApplication>
    
  5. 同様に、App.xaml.cs を開き、内容を次のコードに置き換えます。

    namespace MyUWPApp
    {
        public sealed partial class App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
        {
            public App()
            {
                this.Initialize();
            }
        }
    }
    
  6. MainPage.xaml ファイルと MainPage.xaml.cs ファイルを削除します。

  7. MyUWPApp プロジェクトをビルドします。

MyWPFApp で、MyUWPApp プロジェクトへの参照を追加します。

  1. MyWPFApp のプロジェクト ファイルで、次のように互換性のあるフレームワーク バージョンを指定します。

    1. ソリューション エクスプローラーで、MyWPFApp プロジェクト ノードをクリックして、エディターでプロジェクト ファイルを開きます。

    2. 最初の [PropertyGroup] 要素内に、次の子要素を追加します。 必要に応じて値の 19041 という部分を変更し、MyWPFApp プロジェクトのターゲットおよび最小 OS ビルドに一致させます。

      <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
      
  2. ソリューションエクスプローラーで、[MyWPFApp] > [依存関係] を右クリックし、[プロジェクト参照の追加] を選択して、MyUWPApp プロジェクトへの参照を追加します。

MyWPFApp のエントリ ポイントで XamlApplication オブジェクトをインスタンス化する

次に、MyWPFApp のエントリ ポイントにコードを追加して、MyUWPApp で定義した App クラス (XamlApplication から派生したクラス) のインスタンスを作成します。

  1. MyWPFApp プロジェクト ノードを右クリックし、[追加]>[新しい項目] を選択して、[クラス] を選択します。 [名前]Program.cs に設定し、[追加] をクリックします。

  2. Program.cs の内容を次の XAML に置き換えます (次に、ファイルを保存し、MyWPFApp プロジェクトをビルドします)。

    namespace MyWPFApp
    {
        public class Program
        {
            [System.STAThreadAttribute()]
            public static void Main()
            {
                using (new MyUWPApp.App())
                {
                    var app = new MyWPFApp.App();
                    app.InitializeComponent();
                    app.Run();
                }
            }
        }
    }
    
  3. MyWPFApp プロジェクト ノードを右クリックし、[プロパティ] を選択します。

  4. [アプリケーション]>[全般] で、[スタートアップ オブジェクト] ドロップダウンをクリックし、MyWPFApp.Program (追加した Program クラスの完全修飾名) を選択します。 表示されない場合は、Visual Studio を閉じてから開き直してみてください。

    注意

    既定では、WPF プロジェクトは、生成されるコード ファイルで Main エントリ ポイント関数を定義しますが、これは、変更を意図されていません。 上のステップでは、プロジェクトのエントリ ポイントを新しい Program クラスの Main メソッドに変更します。これにより、アプリのスタートアップ プロセスの可能な限り早い段階で実行されるコードを追加できるようになります。

  5. プロジェクトのプロパティへの変更を保存します。

ラップされたコントロールを使用して InkCanvas と InkToolbar をホストする

UWP XAML Islands を使用するようにプロジェクトを構成したので、InkCanvas および InkToolbar のラップされた UWP XAML コントロールをアプリに追加できます。

  1. MyWPFApp で、MainWindow.xaml ファイルを開きます。

  2. XAML ファイルの先頭近くにある Window 要素に、次の属性を追加します。 この属性は、InkCanvas および InkToolbar のラップされた UWP XAML コントロールの XAML 名前空間を参照し、それをコントロールの XML 名前空間にマッピングします。

    xmlns:controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls"
    
  3. 引き続き MainWindow.xaml で、次の XAML のように既存の 要素を編集します。 この XAML は、グリッドInkCanvas および InkToolbar コントロールを追加します (前の手順で定義した コントロールの XML 名前空間のプレフィックスが付けられます)。

    <Grid Margin="10,50,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <controls:InkToolbar x:Name="myInkToolbar" TargetInkCanvas="{x:Reference myInkCanvas}" Grid.Row="0" Width="300"
            Height="50" Margin="10,10,10,10" HorizontalAlignment="Left" VerticalAlignment="Top" />
        <controls:InkCanvas x:Name="myInkCanvas" Grid.Row="1" HorizontalAlignment="Left" Width="600" Height="400"
            Margin="10,10,10,10" VerticalAlignment="Top" />
    </Grid>
    

    注意

    また、[ツールボックス][Windows Community Toolkit] セクションからデザイナーにドラッグすることで、これらのコントロールや他のラップされたコントロールをウィンドウに追加することもできます。

  4. MainWindow.xaml を保存します。

    Surface のようなデジタル ペンをサポートするデバイスがあり、物理コンピューターで手順を実行している場合は、アプリをビルドして実行し、ペンを使用して画面にデジタル インクを描画できます。 しかし、既定では InkCanvas はデジタルペンに対してのみ有効になるため、マウスを使用して書き込もうとしても何も起こりません。 マウスに対して InkCanvas を有効にする方法を次に示します。

  5. 引き続き MyWPFApp で、MainWindow.xaml.cs を開きます。

  6. 次の名前空間ディレクティブをファイルの先頭に追加します。

    using Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT;
    
  7. MainWindow コンストラクターを見つけます。 InitializeComponent の呼び出しの直後に、次のコード行を追加します。

    myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen;
    

    InkPresenter オブジェクトを使用して、既定のインク エクスペリエンスをカスタマイズできます。 上のコードでは、InputDeviceTypes プロパティを使用して、マウスおよびペン入力を有効にします。

  8. 保存して、ビルドし、実行します。 コンピューターとマウスを使用している場合は、マウスを使用してインク キャンバス スペースに描画できることを確認します。

ホスト コントロールを使用して CalendarView をホストする

このセクションでは、WindowsXamlHost コントロールを使用して、CalendarView をアプリに追加します。

注意

WindowsXamlHost コントロールは、Microsoft.Toolkit.Wpf.UI.XamlHost パッケージによって提供されます。 このパッケージは、前にインストールした Microsoft.Toolkit.Wpf.UI.Controls パッケージに含まれています。

  1. ソリューション エクスプローラーを使用し、MyWPFAppMainWindow.xaml ファイルを開きます。

  2. XAML ファイルの先頭近くにある Window 要素に、次の属性を追加します。 この属性は、WindowsXamlHost コントロールの XAML 名前空間を参照し、それを xamlhost XML 名前空間にマップします。

    xmlns:xamlhost="clr-namespace:Microsoft.Toolkit.Wpf.UI.XamlHost;assembly=Microsoft.Toolkit.Wpf.UI.XamlHost"
    
  3. 引き続き MainWindow.xaml で、次の XAML のように既存の 要素を編集します。 この XAML は、グリッドWindowsXamlHost コントロールを追加します (前の手順で定義した xamlhostの XML 名前空間のプレフィックスが付けられます)。 UWP の CalendarView コントロールをホストするため、この XAML では InitialTypeName プロパティをコントロールの完全修飾名に設定します。 この XAML では、ホストされているコントロールがレンダリングされると発生する ChildChanged イベントのイベント ハンドラーも定義されています。

    <Grid Margin="10,50,10,10">
        <xamlhost:WindowsXamlHost x:Name="myCalendar" InitialTypeName="Windows.UI.Xaml.Controls.CalendarView"
              Margin="10,10,10,10" Width="600" Height="300" ChildChanged="MyCalendar_ChildChanged" />
    </Grid>
    
  4. MainWindow.xaml を保存し、MainWindow.xaml.cs を開きます。

  5. 前のセクションで追加した、次のコード行を削除します。myInkCanvas.InkPresenter.InputDeviceTypes = CoreInputDeviceTypes.Mouse | CoreInputDeviceTypes.Pen;

  6. 次の名前空間ディレクティブをファイルの先頭に追加します。

    using Microsoft.Toolkit.Wpf.UI.XamlHost;
    
  7. 次の Childchanged イベント ハンドラー メソッドを MainWindow クラスに追加します。 ホスト コントロールがレンダリングされると、このイベント ハンドラーが実行され、カレンダー コントロールの SelectedDatesChanged イベント用の簡単なイベント ハンドラーが作成されます。

    private void MyCalendar_ChildChanged(object sender, EventArgs e)
    {
        WindowsXamlHost windowsXamlHost = (WindowsXamlHost)sender;
    
        var calendarView =
            (Windows.UI.Xaml.Controls.CalendarView)windowsXamlHost.Child;
    
        if (calendarView != null)
        {
            calendarView.SelectedDatesChanged += (obj, args) =>
            {
                if (args.AddedDates.Count > 0)
                {
                    MessageBox.Show("The user selected a new date: " +
                        args.AddedDates[0].DateTime.ToString());
                }
            };
        }
    }
    
  8. 保存して、ビルドし、実行します。 カレンダー コントロールがウィンドウに表示されること、および日付を選択したときにメッセージ ボックスが表示されることを確認します。

アプリをパッケージ化する

必要に応じて、展開用に WPF アプリを MSIX パッケージにパッケージ化することもできます。 MSIX は、Windows 用の最新で信頼性の高いアプリ パッケージ テクノロジです。

次の手順では、Visual Studio で Windows アプリケーション パッケージ プロジェクトを使用して、ソリューション内のすべてのコンポーネントを MSIX パッケージにパッケージ化する方法について説明します (「Visual Studio で MSIX パッケージ化するためのデスクトップ アプリケーションの設定」を参照してください)。 これらの手順は、WPF アプリを MSIX パッケージにパッケージ化する場合にのみ必要です。

注意

展開用にアプリケーションを MSIX パッケージにパッケージ化しない場合は、アプリを実行するコンピューターに Visual C++ ランタイムがインストールされている必要があります。

  1. Windows アプリケーション パッケージ プロジェクト プロジェクト テンプレートから作成されたソリューションに新しいプロジェクトを追加します。 プロジェクトを作成するときに、UWP プロジェクトに選択したのと同じ ターゲット バージョン最小バージョンを選択します。

  2. パッケージ プロジェクトで、[依存関係] ノードを右クリックし、[プロジェクト参照の追加] を選択します。プロジェクトの一覧で [MyWPFApp] を選択し、[OK] をクリックします。

    注意

    Microsoft Store でアプリを公開したい場合は、パッケージ プロジェクトに UWP プロジェクトへの参照も追加する必要があります。

  3. この時点までの手順に従った場合、ソリューション内のすべてのプロジェクトが同じ特定のプラットフォーム (x86 または x64) を対象とします。 Windows アプリケーション パッケージ プロジェクトを使用して MSIX パッケージに WPF アプリをビルドするには、このようにする必要があります。 これを確認するには、次の手順を実行します。

    1. ソリューション エクスプローラーでソリューション ノード (プロジェクト ノードではありません) を右クリックし、[プロパティ] を選択します。
    2. 左側の [構成プロパティ] を選択します。
    3. [構成マネージャー] ボタンをクリックします。
    4. [プラットフォーム] で、一覧表示されているすべてのプロジェクトの値が同じ (x86 または x64) であることを確認します。
  4. 追加したパッケージ プロジェクトのプロジェクト ノードを右クリックし、[スタートアップ プロジェクトに設定] をクリックします。

  5. パッケージ プロジェクトをビルドして実行します。 WPF アプリが実行され、UWP コントロールが想定どおりに表示されることを確認します。

  6. パッケージの配布/展開の詳細については、「MSIX の展開を管理する」を参照してください。