條件式 XAML

條件式 XAML 提供直接在 XAML 標記中使用 ApiInformation.IsApiContractPresent 方法的方法。 你可以根據作業系統層級 API 合約的存在設定屬性,而不必在背後寫程式碼。 條件語句在執行時被評估——若條件性 XAML 標籤的元素評值為 true ,則解析,否則忽略。

從 Windows 應用程式 SDK 2.0 開始,你也可以透過實作 IXamlCondition 介面來定義自己的條件。 自訂條件允許你根據應用程式的特定狀態(如功能旗標或設定設定)加入或排除標記。 更多資訊請參見 「建立自訂條件」。

條件式 XAML 需要 Windows 10 版本 1809(版本 17763)或更新版本,這是 Windows 應用程式 SDK 應用程式的最低作業系統版本。

先決條件

Important

內建的條件方法使用ApiInformation方法,檢查作業系統提供的 Windows 執行階段(Windows.*)API 合約與型別是否存在。 這些檢查不適用於 WinUI 3 (Microsoft.UI.Xaml.*) 控制項,因為 WinUI 3 是透過 Windows 應用程式 SDK 隨應用程式出貨,而非作業系統——無論裝置運行哪個 Windows 10/11 版本,應用程式所使用的每個 WinUI 3 控制項在執行時都會存在。 #if預處理器指令在這裡也沒什麼幫助:它們是在編譯時根據目標框架評估,而不是執行時根據實際安裝的作業系統或 Windows 應用程式 SDK 版本來評估。 若要根據應用程式目前執行所依據的 Windows 應用程式 SDK 版本來決定是否啟用某項功能,請在建置時檢查 SDK 版本,或在 API 呼叫外層使用 try/catch。 詳情請參見 版本自適應程式碼 。

關於 API 合約的背景資訊 ApiInformation ,請參見 版本自適應應用程式。

條件命名空間

要在 XAML 中使用條件方法,請在頁面頂端宣告一個條件式 XAML 命名空間 :

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

分隔符前 ? 的內容是命名空間或結構。 ? 後面的內容是條件式方法,用來決定命名空間會評估為 true 或 false。

在大多數情況下,該結構是預設的 XAML 命名空間:

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

條件式 XAML 支援以下條件式方法:

方法 反向
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 支援的最低作業系統版本是 1809(UniversalApiContract版本 7),因此在 Windows 應用程式 SDK 應用程式中,檢查合約版本是否為 7 或更低版本,結果一律會評估為 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)"

然後設定屬性兩次,每次都用不同的條件前綴。 執行時僅套用其中一種:

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

有條件地建立控制項

Note

根據作業系統 API 合約條件實例化 元素 ,而非條件設定 屬性 ,是 UWP 特有的模式。 這不適用於 WinUI 3 的控制項。

在 UWP 中,這個模式讓你在作業系統上沒有新控制項時,可以回退到舊 Windows.UI.Xaml.Controls 的控制項。 在 Windows 應用程式 SDK 應用程式中,WinUI 3 的控制項Microsoft.UI.Xaml.Controls.*()是透過 Windows 應用程式 SDK 隨應用程式一同發佈,而不是透過作業系統。 你的應用程式所依賴的每一個控制——包括 ColorPicker ——都保證在執行時就存在,因此在實例化前不需要檢查作業系統版本。

如果你需要根據應用程式目標的 Windows 應用程式 SDK 版本來限制 WinUI 3 控制項或 API 的使用,請在建置時進行檢查(方法是將目標設為最低支援的 Windows 應用程式 SDK 套件版本),或將執行階段呼叫包在 try/catch 中,而不要使用條件式 XAML。

若要根據應用程式定義的邏輯(如功能標誌)加入或排除元素,請使用 自訂條件。

建立自訂條件

從 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 Gallery 範例的範例,評估應用程式儲存在字典中的特徵旗標:

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;
    }
}

為條件宣告一個條件式命名空間

首先,透過 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)"

在這個例子中,解析器對使用 newExp 前綴的標記呼叫 Evaluate("NewExperience"),以及對使用 legacy 前綴的標記呼叫 Evaluate("LegacyMode")。

在元素、屬性和設定器上使用條件

像使用內建條件命名空間一樣使用條件前綴。 這些範例基於 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

  • 兩個元素不可能有相同的 x:Name,即使執行時只包含其中一個元素。
  • 如果你對同一屬性套用多個條件,請確保執行時只有其中一個條件會評估為 true。 若超過一個項目評估結果為 true,解析器會拋出例外。
  • 由於條件是在執行時評估,XAML 編譯器無法檢查其邏輯一致性。 測試應用程式支援的每種條件值組合。
  • 自訂條件無法用於 http://schemas.microsoft.com/winfx/2006/xaml 命名空間(x:)中的項目,例如 x:Uid 和 x:Key。