Условный код XAML
Условный код XAML обеспечивает возможность использовать метод ApiInformation.IsApiContractPresent в разметке XAML. Благодаря этому можно задавать свойства и создавать экземпляры объектов в разметке в зависимости от наличия API, а необходимость использования кода программной части отсутствует. Условный код XAML выполняет выборочный анализ элементов или атрибутов, чтобы определить, будут ли они доступны во время выполнения. Условные операторы оцениваются во время выполнения, и если в результате оценки получено значение 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 поддерживает приведенные ниже условные методы.
Способ | Inverse |
---|---|
IsApiContractPresent(ContractName, VersionNumber) | IsApiContractNotPresent(ContractName, VersionNumber) |
IsTypePresent(ControlType) | IsTypeNotPresent(ControlType) |
IsPropertyPresent(ControlType, PropertyName) | IsPropertyNotPresent(ControlType, PropertyName) |
Мы рассмотрим эти методы позже, в следующих разделах этой статьи.
Примечание.
Рекомендуется использовать методы IsApiContractPresent и IsApiContractNotPresent. Другие условные методы не полностью поддерживаются в среде разработки Visual Studio.
Создание пространства имен и задание свойства
В этом примере необходимо отобразить текст "Hello, Conditional XAML" в качестве содержимого текстового блока, если приложение выполняется в версии Fall Creators Update или более поздней версии, и по умолчанию не отображать никакого содержимого, если приложение выполняется в предыдущей версии операционной системы.
Во-первых, определите пользовательское пространство имен с префиксом contract5Present и используйте пространство имен XAML по умолчанию (https://schemas.microsoft.com/winfx/2006/xaml/presentation
) в качестве схемы со свойством TextBlock.Text. Чтобы сделать это пространство имен условным, добавьте разделитель "?" после схемы.
Затем определите условный оператор, возвращающий значение true на устройствах с обновлением Fall Creators Update или выше. Используйте метод ApiInformation IsApiContractPresent для проверки наличия 5-й версии UniversalApiContract. Версия 5 UniversalApiContract была выпущена вместе с обновлением Fall Creators Update (пакет SDK 16299).
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
Определив пространство имен, добавьте префикс пространства имен перед свойством Text элемента TextBox, чтобы указать, что это свойство необходимо задать условно во время выполнения.
<TextBlock contract5Present:Text="Hello, Conditional XAML"/>
Ниже приводится полный код 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: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
В предыдущем примере свойство Text задается, только если приложение выполняется в версии Fall Creators Update. Но что делать, если нужно отобразить другой текст при выполнении приложения в версии 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 с 4-й версией универсального контракта API.
Разные вызовы ApiContractPresent дадут следующие результаты.
- 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
Чтобы использовать обратное условие, необходимо создать второе условное пространство имен XAML, использующее условный оператор IsApiContractNotPresent. В этом примере он имеет префикс 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"/>
Ниже приведен еще один пример, в котором настраивается фон кнопки. Функция Acrylic material (Акриловый материал) доступна, начиная с версии Fall Creators Update, поэтому вы будете использовать акриловый фон, когда приложение выполняется в версии Fall Creators Update. В более ранних версиях эта функция недоступна, поэтому для этих случаев вы задаете красный фон.
<Button Content="Button"
contract5NotPresent:Background="Red"
contract5Present:Background="{ThemeResource SystemControlAcrylicElementBrush}"/>
Создание элементов управления и привязка свойств
До этого момента мы рассматривали настройку свойств с использованием условного кода XAML, однако можно также условно создавать экземпляры элементов управления на основе доступного во время выполнения контракта API.
В этом примере создается экземпляр элемента управления ColorPicker, если приложение выполняется в версии Fall Creators Update, где доступен этот элемент управления. Элемент управления 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. В этом примере свойство Fill прямоугольника задается с использованием синтаксиса элементов свойств для Fall Creators Update и синтаксиса атрибутов для предыдущих версий.
<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, демонстрирующий эти сценарии. В этом примере демонстрируется прямоугольник и пользовательский интерфейс, позволяющий задать цвет прямоугольника.
Если приложение выполняется в версии Fall Creators Update, чтобы предоставить пользователю возможность выбрать цвет, используется элемент управления ColorPicker. Элемент управления ColorPicker недоступен в версиях, предшествующих Fall Creators Update, поэтому если приложение выполняется в более ранних версиях, для упрощенного выбора цвета пользователю предоставляется элемент управления ComboBox.
<Page
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>