条件 XAML 提供在 XAML 标记中使用
ApiInformation.IsApiContractPresent
方法的一种途径。 可以在 API 存在的情况下在标记中设置属性和实例化对象,无需使用代码隐藏。 它选择性地分析元素或属性来确定它们在运行时是否可用。 条件语句在运行时进行评估。如果评估为
true
,则会对使用条件 XAML 标记进行限定的元素进行分析;否则会忽略它们。
条件 XAML 从 Creators Update(版本 1703,内部版本 15063)开始提供。 若要使用条件 XAML,Visual Studio 项目的最低版本必须设置为内部版本 15063 (Creators Update) 或更高版本,且目标版本必须设置为比最低版本更高的版本。 请参阅
版本自适应应用
,详细了解如何配置 Visual Studio 项目。
若要使用低于内部版本 15063 的最低版本创建版本自适应应用,则必须使用
版本自适应代码
,而不是 XAML。
有关 ApiInformation 和 API 协定的重要背景信息,请参阅
版本自适应应用
。
条件命名空间
若要在 XAML 中使用条件方法,首先必须在页面顶部声明条件
XAML 命名空间
。 下面介绍条件命名空间的伪代码示例:
xmlns:myNamespace="schema?conditionalMethod(parameter)"
条件命名空间可以分为两部分,用“?”分隔符分隔。
分隔符前面的内容指示命名空间或架构含有被引用的 API。
分隔符“?”后的内容表示条件方法,该方法确定是将条件命名空间评估为 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)
我们将在本文后面的部分中进一步讨论这些方法。
我们建议你使用 IsApiContractPresent 和 IsApiContractNotPresent。 其他条件在 Visual Studio 设计体验中不完全受支持。
创建命名空间并设置一个属性
在此示例中,如果在 Fall Creators Update 或更高版本上运行应用,将显示“Hello, Conditional XAML”作为文本块的内容;如果在以前的版本上运行,则默认显示无内容。
首先,使用前缀“contract5Present”定义自定义命名空间并使用默认 XAML 命名空间 (https://schemas.microsoft.com/winfx/2006/xaml/presentation
) 作为含有 TextBlock.Text 属性的架构。 若要使其成为一个条件命名空间,请在架构后添加“?” 分隔符。
然后定义在运行 Fall Creators Update 或更高版本的设备上返回 true 的条件。 使用 ApiInformation 方法 IsApiContractPresent 来检查 UniversalApiContract 的第 5 个版本。 UniversalApiContract 版本 5 和 Fall Creators Update (SDK 16299) 一起发布。
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
定义命名空间后,将命名空间前缀添加到 TextBox 的 Text 属性的前面,将它限定为应该在运行时进行条件性设置的属性。
<TextBlock contract5Present:Text="Hello, Conditional XAML"/>
下面是完整的 XAML。
x:Class="ConditionalTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock contract5Present:Text="Hello, Conditional XAML"/>
</Grid>
</Page>
在 Fall Creators Update 上运行此示例时,显示文本“Hello, Conditional XAML”;在 Creators Update 上运行时,不显示文本。
条件 XAML 可以让你改为在标记中执行可针对代码执行的 API 检查。 下面介绍此检查的等效代码。
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 5))
textBlock.Text = "Hello, Conditional XAML";
请注意,即使 IsApiContractPresent 方法带有一个表示 contractName 参数的字符串,也不应将它放在 XAML 命名空间声明的引号 (" ") 中。
使用 if/else 条件
在上面的示例中,仅当在 Fall Creators Update 上运行应用时设置 Text 属性。 但是,当它在 Creators Update 上运行时,如果你想要显示不同的文本,应该怎么做? 可以尝试在不使用条件限定符的情况下设置 Text 属性,如下所示。
<!-- DO NOT USE -->
<TextBlock Text="Hello, World" contract5Present:Text="Hello, Conditional XAML"/>
当它在 Creators Update 上运行时,这会有效;但在 Fall Creators Update 上运行时,你会收到错误消息,指出 Text 属性已设置多次。
当应用在不同版本的 Windows 10 上运行时,若要设置不同的文本,你需要另一个条件。 条件 XAML 提供每种受支持的 ApiInformation 方法的反转,让你创建类似这样的 if/else 条件方案。
如果当前设备包含指定合同和版本号,IsApiContractPresent 方法会返回 true。 例如,假设在 Creators Update 上运行应用,它具有通用 API 协定第 4 版。
对 IsApiContractPresent 的不同调用会产生以下结果:
IsApiContractPresent(Windows.Foundation.UniversalApiContract, 5) = false
IsApiContractPresent(Windows.Foundation.UniversalApiContract, 4) = true
IsApiContractPresent(Windows.Foundation.UniversalApiContract, 3) = true
IsApiContractPresent(Windows.Foundation.UniversalApiContract, 2) = true
IsApiContractPresent(Windows.Foundation.UniversalApiContract, 1) = true。
IsApiContractNotPresent 返回 IsApiContractPresent 的反转。 调用 IsApiContractNotPresent 会产生以下结果:
IsApiContractNotPresent(Windows.Foundation.UniversalApiContract, 5) = true
IsApiContractNotPresent(Windows.Foundation.UniversalApiContract, 4) = false
IsApiContractNotPresent(Windows.Foundation.UniversalApiContract, 3) = false
IsApiContractNotPresent(Windows.Foundation.UniversalApiContract, 2) = false
IsApiContractNotPresent(Windows.Foundation.UniversalApiContract, 1) = false
若要使用反转条件,可以创建第二个使用 IsApiContractNotPresent 条件的条件 XAML 命名空间。 在这里,其中包含前缀“contract5NotPresent”。
xmlns:contract5NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,5)"
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
定义两个命名空间后,可以将 Text 属性设置两次,前提是在它们前面添加限定符,确保在运行时仅使用一个属性设置,如下所示:
<TextBlock contract5NotPresent:Text="Hello, World"
contract5Present:Text="Hello, Fall Creators Update"/>
下面介绍了设置按钮背景的另一个示例。 亚克力材料功能从 Fall Creators Update 开始提供,因此当在 Fall Creators Update 上运行应用时,你将为背景使用亚克力。 它在更早的版本中不可用,因此在这些情况下,要将背景设置为红色。
<Button Content="Button"
contract5NotPresent:Background="Red"
contract5Present:Background="{ThemeResource SystemControlAcrylicElementBrush}"/>
创建控件和绑定属性
到目前为止,你已了解如何使用条件 XAML 设置属性,但你也可基于在运行时可用的 API 协定条件性地实例化控件。
在这里,当在控件可用的 Fall Creators Update 上运行应用时,对 ColorPicker 进行实例化。 ColorPicker 在 Fall Creators Update 之前不可用,因此在较早的版本上运行应用时,使用 ComboBox 为用户提供简化的颜色选项。
<contract5Present:ColorPicker x:Name="colorPicker"
Grid.Column="1"
VerticalAlignment="Center"/>
<contract5NotPresent:ComboBox x:Name="colorComboBox"
PlaceholderText="Pick a color"
Grid.Column="1"
VerticalAlignment="Center">
可以使用具有不同形式的 XAML 属性语法的条件限定符。 在这里,使用用于 Fall Creators Update 的属性元素句法和用于较早版本的属性句法设置矩形的 Fill 属性。
<Rectangle x:Name="colorRectangle" Width="200" Height="200"
contract5NotPresent:Fill="{x:Bind ((SolidColorBrush)((FrameworkElement)colorComboBox.SelectedItem).Tag), Mode=OneWay}">
<contract5Present:Rectangle.Fill>
<SolidColorBrush contract5Present:Color="{x:Bind colorPicker.Color, Mode=OneWay}"/>
</contract5Present:Rectangle.Fill>
</Rectangle>
将属性绑定到取决于条件命名空间的另一个属性时,必须对这两个属性使用相同的条件。 在这里,colorPicker.Color
取决于“contract5Present”条件命名空间,因此必须将“contract5Present”前缀放在 SolidColorBrush.Color 属性的前面。 (或者将“contract5Present”前缀放在 SolidColorBrush 的前面,而不是放在 Color 属性的前面。)否则会出现编译时间错误。
<SolidColorBrush contract5Present:Color="{x:Bind colorPicker.Color, Mode=OneWay}"/>
下面是演示这些方案的完整 XAML。 此示例中包含一个矩形以及一个让你设置矩形颜色的 UI。
在 Fall Creators Update 上运行应用时,使用 ColorPicker 让用户设置颜色。 ColorPicker 在 Fall Creators Update 之前不可用,因此在较早的版本上运行应用时,使用组合框为用户提供简化的颜色选项。
x:Class="ConditionalTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
xmlns:contract5NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,5)">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="colorRectangle" Width="200" Height="200"
contract5NotPresent:Fill="{x:Bind ((SolidColorBrush)((FrameworkElement)colorComboBox.SelectedItem).Tag), Mode=OneWay}">
<contract5Present:Rectangle.Fill>
<SolidColorBrush contract5Present:Color="{x:Bind colorPicker.Color, Mode=OneWay}"/>
</contract5Present:Rectangle.Fill>
</Rectangle>
<contract5Present:ColorPicker x:Name="colorPicker"
Grid.Column="1"
VerticalAlignment="Center"/>
<contract5NotPresent:ComboBox x:Name="colorComboBox"
PlaceholderText="Pick a color"
Grid.Column="1"
VerticalAlignment="Center">
<ComboBoxItem>Red
<ComboBoxItem.Tag>
<SolidColorBrush Color="Red"/>
</ComboBoxItem.Tag>
</ComboBoxItem>
<ComboBoxItem>Blue
<ComboBoxItem.Tag>
<SolidColorBrush Color="Blue"/>
</ComboBoxItem.Tag>
</ComboBoxItem>
<ComboBoxItem>Green
<ComboBoxItem.Tag>
<SolidColorBrush Color="Green"/>
</ComboBoxItem.Tag>
</ComboBoxItem>
</contract5NotPresent:ComboBox>
</Grid>
</Page>
UWP 应用指南
使用 API 合约动态检测功能
使用扩展 SDK 编程