ContentIsland

ContentIslandは WinUI 3 および Windows アプリ SDK API であり、コンポジション ビジュアル、Win2D コンテンツ、Direct3D サーフェスなどの非 XAML レンダリング コンテンツを WinUI 3 アプリ内でホストできます。 各島は、独自の入力、出力、レイアウト、およびアクセシビリティの状態を持つ分離されたレンダリング サーフェイスです。 ChildSiteLinkを使用して、子島を親島内の場所に接続します。

標準の XAML 要素として表現されていないコンテンツが必要な高度な相互運用シナリオでは、 ContentIsland を使用します。

Note

ContentIsland は、高度なレンダリング シナリオを対象としています。 ほとんどのアプリ UI では、標準の WinUI 3 XAML コントロールを使用します。

ContentIsland のしくみ

WinUI 3 XAML アプリは、 ContentIsland内で既に実行されています。 XamlRoot.ContentIslandから親の島を取得できます。 XAML ツリー内に追加の XAML 以外のコンテンツを配置するには、次の手順を実行します。

  1. XAML でスペースを確保する。
  2. 親アイランド内に配置用ビジュアルを作成します。
  3. その配置ビジュアルの ChildSiteLink を作成します。
  4. 独自のルート ビジュアルを使用して子 ContentIsland を作成します。
  5. 子アイランドを接続し、そのサイズと変換を XAML レイアウトと同期します。

その後、子アイランドは、コンポジション コンテンツ、Win2D 描画、Direct3D ベースのビジュアル、またはその他の XAML 以外のレンダリング コンテンツをホストできます。

XAML で領域を予約する

ルート コンテナーと、子アイランドが表示されるプレースホルダー要素から始めます。

<Grid x:Name="RootPanel">
    <Border x:Name="IslandHost"
            Width="320"
            Height="200"
            HorizontalAlignment="Left"
            VerticalAlignment="Top" />
</Grid>

子島を作成する

親の島に配置ビジュアルを作成し、子島を作成して接続します。

using System.Numerics;
using Microsoft.UI.Composition;
using Microsoft.UI.Content;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Hosting;

private ChildSiteLink? _childSiteLink;
private ContentIsland? _childIsland;
private ContainerVisual? _placementVisual;
private ContainerVisual? _childRootVisual;

private void CreateContentIsland()
{
    ContentIsland parentIsland = IslandHost.XamlRoot.ContentIsland;
    Compositor compositor = ElementCompositionPreview.GetElementVisual(RootPanel).Compositor;

    // This visual marks where the child island appears inside the parent island.
    _placementVisual = compositor.CreateContainerVisual();
    ElementCompositionPreview.SetElementChildVisual(RootPanel, _placementVisual);

    _childSiteLink = ChildSiteLink.Create(parentIsland, _placementVisual);

    // Create the root visual for the child island's own scene graph.
    _childRootVisual = compositor.CreateContainerVisual();
    _childIsland = ContentIsland.Create(_childRootVisual);

    _childSiteLink.Connect(_childIsland);

    UpdateContentIslandLayout();
}

ContentIsland.Create は、アイランドのシーンのルートとなる Visual を受け取ります。 島が接続されたら、そのルート ビジュアルの下にコンポジション コンテンツを追加できます。

XAML 要素を基準にして島を配置する

配置ビジュアルと ChildSiteLink をプレースホルダー要素と同期したままにします。 次の使用例は、プレースホルダーの境界をルート パネルにマップし、配置ビジュアルとリンクの両方を更新します。

using System.Numerics;
using Windows.Foundation;

private void UpdateContentIslandLayout()
{
    if (_placementVisual is null || _childSiteLink is null)
    {
        return;
    }

    GeneralTransform transform = IslandHost.TransformToVisual(RootPanel);
    Point position = transform.TransformPoint(new Point(0, 0));

    Vector2 size = new((float)IslandHost.ActualWidth, (float)IslandHost.ActualHeight);
    Vector3 offset = new((float)position.X, (float)position.Y, 0);

    _placementVisual.Offset = offset;
    _placementVisual.Size = size;

    _childSiteLink.ActualSize = size;
    _childSiteLink.LocalToParentTransformMatrix =
        Matrix4x4.CreateTranslation(offset);
}

レイアウトの変更を同期する

子アイランドが XAML プレースホルダーに合わせて配置されるように、レイアウトの変更をサブスクライブします。

public MainPage()
{
    this.InitializeComponent();

    // XamlRoot is null until the element is in the visual tree.
    // Defer ContentIsland creation to the Loaded event.
    IslandHost.Loaded += OnIslandHostLoaded;
    IslandHost.LayoutUpdated += OnIslandHostLayoutUpdated;
    IslandHost.Unloaded += OnIslandHostUnloaded;
}

private void OnIslandHostLoaded(object sender, RoutedEventArgs e)
{
    IslandHost.Loaded -= OnIslandHostLoaded;
    CreateContentIsland();
}

private void OnIslandHostLayoutUpdated(object sender, object e)
{
    UpdateContentIslandLayout();
}

プレースホルダーをアニメーション化またはサイズ変更する場合は、有効なサイズまたは位置が変更されるたびに UpdateContentIslandLayout を呼び出します。

子島にコンテンツを追加する

子アイランドを作成したら、子ルート ビジュアルの下にコンポジション コンテンツを追加します。

private void AddSpriteVisual()
{
    if (_childRootVisual is null)
    {
        return;
    }

    Compositor compositor = _childRootVisual.Compositor;

    SpriteVisual sprite = compositor.CreateSpriteVisual();
    sprite.Size = new Vector2(320, 200);
    sprite.Brush = compositor.CreateColorBrush(Microsoft.UI.Colors.DodgerBlue);

    _childRootVisual.Children.InsertAtTop(sprite);
}

SpriteVisualは、独自の Win2D または Direct3D ベースのビジュアル ツリーに置き換えることができます。

島をクリーンアップする

ContentIslandChildSiteLink は、クロス可能なリソースです。 不要になったら閉じるか破棄します。

private void OnIslandHostUnloaded(object sender, RoutedEventArgs e)
{
    IslandHost.LayoutUpdated -= OnIslandHostLayoutUpdated;
    IslandHost.Unloaded -= OnIslandHostUnloaded;

    _childIsland?.Close();
    _childSiteLink?.Close();

    _childIsland = null;
    _childSiteLink = null;
    _placementVisual = null;
    _childRootVisual = null;
}

レンダリング リソースをすぐに解放できるように、 Unloaded またはウィンドウのシャットダウン中にクリーンアップを処理します。

WinUI 3 ギャラリー アプリには、多くの WinUI 3 コントロールとプラットフォーム機能の対話型の例が含まれています。