条件付き XAML

条件付き XAML は、 APIInformation.IsApiContractPresent メソッドを XAML マークアップで直接使用する方法を提供します。 コード ビハインドを記述することなく、OS レベルの API コントラクトの存在に基づいてプロパティを設定できます。 条件付きステートメントは実行時に評価されます。条件付き XAML タグで修飾された要素は、 true に評価された場合は解析され、それ以外の場合は無視されます。

Windows アプリ SDK 2.0 以降では、IXamlCondition インターフェイスを実装して独自の条件を定義することもできます。 カスタム条件を使用すると、機能フラグや構成設定など、アプリ固有の状態に基づいてマークアップを含めたり除外したりできます。 詳細については、「 カスタム条件の作成」を参照してください。

条件付き XAML には、Windows 10 バージョン 1809 (ビルド 17763) 以降が必要です。これは、Windows アプリ SDK アプリの最小 OS バージョンです。

前提条件

Important

組み込みの条件付きメソッドではApiInformationメソッドを使用します。これは、OS によって提供されるWindows ランタイム (Windows.*) API コントラクトと型の有無を確認します。 これらのチェックは WinUI 3 () コントロールには適用Microsoft.UI.Xaml.*。WinUI 3 は OS ではなくWindows アプリ SDK経由でアプリに付属しているためです。アプリがビルドされるすべての WinUI 3 コントロールは、デバイスが実行されているWindows 10/11 ビルドに関係なく、常に実行時に存在します。 #ifプリプロセッサ ディレクティブもここでは役に立ちません。これらは、実際にインストールされている OS や Windows アプリ SDK のバージョンではなく、ターゲット フレームワークに基づいてコンパイル時に評価されるためです。 アプリが実行されているWindows アプリ SDKバージョンの機能をゲートするには、ビルド時に SDK のバージョンを確認するか、API 呼び出しの前後で try/catch を使用します。 詳細については、 バージョン アダプティブ コード を参照してください。

ApiInformationおよび API コントラクトの背景情報については、「バージョン アダプティブ アプリ」を参照してください。

条件付き名前空間

XAML で条件付きメソッドを使用するには、ページの上部で条件付き XAML 名前空間 を宣言します。

xmlns:myNamespace="schema?conditionalMethod(parameter)"

?区切り記号の前のコンテンツは、名前空間またはスキーマです。 ?後のコンテンツは、名前空間がtrueまたはfalseに評価されるかどうかを決定する条件付きメソッドです。

ほとんどの場合、スキーマは既定の XAML 名前空間です。

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

条件付き XAML では、次の条件付きメソッドがサポートされています。

Method 逆
IsApiContractPresent(ContractName, VersionNumber) IsApiContractNotPresent(ContractName, VersionNumber)
IsTypePresent(ControlType) IsTypeNotPresent(ControlType)
IsPropertyPresent(ControlType, PropertyName) IsPropertyNotPresent(ControlType, PropertyName)

アプリで定義した条件を使用することもできます。 詳細については、「 カスタム条件の作成」を参照してください。

Note

IsApiContractPresentとIsApiContractNotPresentを使用して、最適なデザイン時エクスペリエンスを実現します。 その他の条件は、Visual Studio設計エクスペリエンスでは完全にはサポートされていません。

条件付きでプロパティを設定する

次の使用例は、Windows 10 バージョン 1903 (2019 年 5 月の更新プログラム、ビルド 18362) 以降でアプリが実行されている場合にのみ、TextBlockにテキストを表示します。これは、Windows アプリ SDKの 1809 フロアよりも新しいため意味のあるコントラクト チェックです。

まず、条件付き名前空間を定義します。

xmlns:contract8Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,8)"

次に、プロパティに条件付き名前空間のプレフィックスを付けます。

<TextBlock contract8Present:Text="Hello, Conditional XAML"/>

完全なマークアップを次に示します。

<Page
    x:Class="ConditionalTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:contract8Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,8)">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock contract8Present:Text="Hello, Conditional XAML"/>
    </Grid>
</Page>

コード ビハインドでの同等のチェック:

TextBlock textBlock = new TextBlock();

if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
{
    textBlock.Text = "Hello, Conditional XAML";
}

Note

IsApiContractPresentはコントラクト名パラメーターの文字列を受け取りますが、XAML 名前空間宣言で引用符で囲むことはありません。

Windows アプリ SDKのサポートされている最小 OS バージョンは 1809 (UniversalApiContract バージョン 7) であるため、7 以下のコントラクト バージョンを確認すると、常にWindows アプリ SDK アプリでtrueが評価され、有用な情報は提供されません。 7 より大きい コントラクト バージョンのみを確認します。

if/else 条件を使用する

API コントラクトに応じて異なる値を設定するには、正と負の両方の条件付き名前空間を定義します。

xmlns:contract8NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,8)"
xmlns:contract8Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,8)"

次に、プロパティを 2 回設定し、それぞれ異なる条件付きプレフィックスを使用します。 実行時に適用されるのは次の 1 つだけです。

<TextBlock contract8NotPresent:Text="Hello, World"
           contract8Present:Text="Hello, May 2019 Update or later"/>

条件付きでコントロールをインスタンス化する

Note

条件付きでプロパティを設定するのではなく、OS API コントラクトに基づいて要素を条件付きでインスタンス化することは、UWP 固有のパターンです。 WinUI 3 コントロールには適用されません。

UWP では、このパターンを使用すると、OS で新しいコントロールを使用できなかった場合に、古い Windows.UI.Xaml.Controls コントロールにフォールバックできます。 Windows アプリ SDK アプリでは、WinUI 3 コントロール (Microsoft.UI.Xaml.Controls.*) は OS ではなく、Windows アプリ SDK経由でアプリに付属します。 アプリがビルドされるすべてのコントロール ( ColorPicker を含む) は実行時に存在することが保証されているため、インスタンス化する前に確認する OS バージョンはありません。

アプリがターゲットとするWindows アプリ SDKのバージョンで WinUI 3 コントロールまたは API をゲートする必要がある場合は、ビルド時にそのチェックを行うか (最小Windows アプリ SDK パッケージ バージョンをターゲットにして)、ランタイム呼び出しを条件付き XAML ではなくtry/catchでラップします。

アプリが定義するロジック (機能フラグなど) に基づいて要素を含めたり除外したりするには、 カスタム条件を使用します。

カスタム条件を作成する

Windows アプリ SDK 2.0 以降では、独自の条件を定義し、条件付き名前空間構文で使用できます。 カスタム条件を使用すると、機能フラグ、構成設定、デバイス機能など、アプリ固有の状態に基づいてマークアップを含めたり除外したりできます。 組み込みの条件付きメソッドと同様に、XAML が実行時に解析されるときにカスタム条件が評価されます。

WinUI 3 ギャラリー アイコン WinUI 3 ギャラリー アプリには、WinUI コントロールと機能の対話型の例が含まれています。 Microsoft Store からアプリを取得するか、GitHub でソース コードを参照します。

Note

IXamlConditionは、Windows アプリ SDK 2.0 の試験的リリースのIXamlPredicate インターフェイスを置き換えます。

条件を設定する

条件を作成するには、DependencyObject から派生し、IXamlCondition を実装するクラスを定義します。 XAML パーサーは Evaluate メソッドを呼び出し、条件付き名前空間宣言のかっこ間のテキストを argument パラメーターとして渡します。 修飾されたマークアップを含める場合は true を返し、無視する場合は false を返します。

この例は、WinUI 3 ギャラリー サンプルから、アプリがディクショナリに格納する機能フラグを評価します。

using System.Collections.Generic;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Markup;

namespace MyApp;

public sealed partial class FeatureFlagCondition : DependencyObject, IXamlCondition
{
    public static IDictionary<string, bool> FeatureFlags { get; } = new Dictionary<string, bool>
    {
        ["NewExperience"] = true,
        ["LegacyMode"] = false,
    };

    // The XAML parser calls Evaluate with the text between the parentheses
    // in the conditional namespace declaration, for example "NewExperience".
    public bool Evaluate(string argument)
    {
        return FeatureFlags.TryGetValue(argument, out bool enabled) && enabled;
    }
}

condition に対して条件付き名前空間を宣言する

まず、 using: 宣言を使用して、条件クラスを含む名前空間をマップします。 次に、条件付き名前空間の ? 区切り記号の後に、そのプレフィックスを使用してクラスを参照し、引数をかっこで囲んで渡します。

xmlns:cond="using:MyApp"
xmlns:newExp="http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(NewExperience)"
xmlns:legacy="http://schemas.microsoft.com/winfx/2006/xaml/presentation?cond:FeatureFlagCondition(LegacyMode)"

この例では、パーサーは、Evaluate("NewExperience") プレフィックスを使用するマークアップに対して newExp を呼び出し、Evaluate("LegacyMode") プレフィックスを使用するマークアップに対して legacy を呼び出します。

要素、属性、セッターの条件を使用する

組み込みの条件付き名前空間を使用するのと同じ方法で、条件付きプレフィックスを使用します。 これらの例は、WinUI 3 ギャラリーサンプルに基づいています。

条件が true の場合にのみ要素を含めるには、要素の先頭にプレフィックスを付けます。

<StackPanel Spacing="8">
    <!-- Included only when FeatureFlagCondition.Evaluate("NewExperience") returns true. -->
    <newExp:InfoBar Title="New experience" IsOpen="True" Severity="Success"
                    Message="This InfoBar is included because the NewExperience flag is true." />

    <!-- Included only when FeatureFlagCondition.Evaluate("LegacyMode") returns true. -->
    <legacy:InfoBar Title="Legacy mode" IsOpen="True" Severity="Warning"
                    Message="This InfoBar is included because the LegacyMode flag is true." />
</StackPanel>

条件が true の場合にのみプロパティを設定するには、属性の前に次のプレフィックスを付けます。

<!-- Make sure that no more than one of these conditions is true at runtime. -->
<Button newExp:Content="Open the new editor"
        legacy:Content="Open the classic editor" />

条件が true の場合にのみスタイル セッターを適用するには、Setter 要素の前にプレフィックスを付けます。

<Page.Resources>
    <Style x:Key="ConditionalHeadingStyle" TargetType="TextBlock">
        <newExp:Setter Property="FontWeight" Value="SemiBold" />
        <newExp:Setter Property="FontSize" Value="28" />
        <legacy:Setter Property="FontWeight" Value="Normal" />
        <legacy:Setter Property="FontSize" Value="18" />
    </Style>
</Page.Resources>

XAML が解析される前に状態を設定する

パーサーは、プロセスの有効期間中、条件と引数の組み合わせごとに Evaluate の結果をキャッシュします。 結果がキャッシュされた後に条件が読み取る状態を変更しても、既に解析されているマークアップは変更されません。後で解析されたマークアップでは、キャッシュされた結果が引き続き使用されます。 別の値を使用するには、アプリを再起動してください。

パーサーがそれを評価する前 (アプリの起動時やページ コンストラクターで InitializeComponent を呼び出す前など) に、条件が読み取る状態を設定します。

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        // Set the flags before InitializeComponent so that the XAML parser
        // uses these values when it evaluates the conditions.
        FeatureFlagCondition.FeatureFlags["NewExperience"] = true;
        FeatureFlagCondition.FeatureFlags["LegacyMode"] = false;

        this.InitializeComponent();
    }
}

Limitations

  • 実行時に含まれる要素が 1 つだけであっても、2 つの要素が同じ x:Nameを持つことはできません。
  • 同じ属性に複数の条件を適用する場合は、実行時にそのうちの 1 つだけが true に評価されることを確認します。 複数のものが true と評価される場合、パーサーは例外をスローします。
  • 条件は実行時に評価されるため、XAML コンパイラでは論理整合性を確認できません。 アプリでサポートされている条件値の各組み合わせをテストしてください。
  • カスタム条件は、x: や http://schemas.microsoft.com/winfx/2006/xaml などの x:Uid 名前空間 (x:Key) の項目では機能しません。