XAML condicional

O XAML condicional fornece uma forma de usar o método ApiInformation.IsApiContractPresent diretamente na marcação XAML. Pode definir propriedades com base na presença de um contrato de API ao nível do sistema operativo sem escrever código por trás. As instruções condicionais são avaliadas em tempo de execução — os elementos qualificados com uma tag XAML condicional são processados caso sejam avaliados como true e ignorados caso contrário.

A partir do SDK de Aplicações Windows 2.0, pode também definir as suas próprias condições implementando a interface IXamlCondition. As condições personalizadas permitem incluir ou excluir markup com base no estado específico da aplicação, como flags de funcionalidades ou definições de configuração. Para mais informações, consulte Criar condições personalizadas.

O XAML condicional requer a versão 1809 do Windows 10 (build 17763) ou posterior, que é a versão mínima do sistema operativo para aplicações do SDK de Aplicações Windows.

Pré-requisitos

Importante

Os métodos condicionais incorporados ApiInformation verificam a presença de contratos e tipos de API do Windows Runtime (Windows.*) fornecidos pelo sistema operativo. Estas verificações não se aplicam aos controlos do WinUI 3 (Microsoft.UI.Xaml.*), porque o WinUI 3 vem com a sua aplicação através do SDK de Aplicações Windows em vez do sistema operativo — todos os controlos do WinUI 3 contra os quais a sua aplicação está construída estão sempre presentes em tempo de execução, independentemente da versão Windows 10/11 que o dispositivo esteja a usar. #ifAs diretivas do pré-processador também não ajudam aqui: são avaliadas em tempo de compilação com base no framework de destino, não em tempo de execução com base no sistema operativo ou na versão do SDK de Aplicações Windows realmente instalada. Para bloquear uma funcionalidade na versão do SDK de Aplicações Windows contra a qual a tua aplicação está a correr, verifica a versão do SDK no momento da compilação ou usa um try/catch para contornar a chamada da API. Consulte o código adaptativo da versão para mais detalhes.

Para informações gerais sobre ApiInformation e contratos de API, consulte aplicações adaptáveis à versão.

Espaços de nomes condicionais

Para usar um método condicional em XAML, declare um namespace XAML condicional no topo da sua página:

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

O conteúdo antes do ? delimitador é o namespace ou esquema. O conteúdo após ? é o método condicional que determina se o namespace avalia como true ou false.

Na maioria dos casos, o esquema é o namespace padrão XAML:

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

O XAML condicional suporta estes métodos condicionais:

Método Inverso
IsApiContractPresent(ContractName, VersionNumber) IsApiContractNotPresent(ContractName, VersionNumber)
IsTypePresent(ControlType) IsTypeNotPresent(ControlType)
IsPropertyPresent(ControlType, PropertyName) IsPropertyNotPresent(ControlType, PropertyName)

Também pode usar uma condição que defina na sua aplicação. Para mais informações, consulte Criar condições personalizadas.

Note

Utilize IsApiContractPresent e IsApiContractNotPresent para uma melhor experiência em tempo de conceção. Outros condicionais não são totalmente suportados na experiência de design do Visual Studio.

Definir uma propriedade condicionalmente

Este exemplo mostra texto num TextBlock apenas quando a aplicação é executada no Windows 10, versão 1903 (Atualização de maio de 2019, build 18362) ou posterior — uma verificação de contrato que faz sentido porque é mais recente do que a versão mínima 1809 do SDK de Aplicações Windows.

Primeiro, defina um espaço de nomes condicional:

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

Depois, prefixe a propriedade com o namespace condicional:

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

Aqui está a margem completa:

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

O código de check-in equivalente abaixo:

TextBlock textBlock = new TextBlock();

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

Note

Mesmo que IsApiContractPresent aceite uma cadeia de caracteres para o parâmetro de nome de contrato, não o deve colocar entre aspas na declaração do espaço de nomes XAML.

Como a versão mínima do SO suportada pelo SDK de Aplicações Windows é a 1809 (UniversalApiContract versão 7), verificar uma versão do contrato igual ou inferior a 7 resulta sempre em true numa aplicação do SDK de Aplicações Windows e não fornece qualquer informação útil. Verifica apenas versões do contrato superiores a 7.

Utilize condições if/else

Para definir valores diferentes dependendo do contrato API, defina tanto os namespaces condicionais positivo como negativo:

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)"

Depois define a propriedade duas vezes, cada uma com um prefixo condicional diferente. Apenas um é aplicado em tempo de execução:

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

Instanciar controlos condicionalmente

Note

Instanciar condicionalmente um elemento com base num contrato da API do OS — em oposição a definir condicionalmente uma propriedade — é um padrão específico do UWP. Não se aplica aos controlos do WinUI 3.

No UWP, este padrão permitia-te voltar a um controlo mais antigo Windows.UI.Xaml.Controls quando um mais recente não estava disponível no sistema operativo. Numa aplicação do SDK de Aplicações Windows, os controlos do WinUI 3 (Microsoft.UI.Xaml.Controls.*) vêm com a sua aplicação através do SDK de Aplicações Windows, não do sistema operativo. Cada controlo contra o qual a sua aplicação é construída — incluindo ColorPicker — está garantido presente em tempo de execução, por isso não há uma versão do sistema operativo para verificar antes de a instanciar.

Se precisares de condicionar a utilização de um controlo ou de uma API do WinUI 3 à versão do SDK de Aplicações Windows visada pela tua aplicação, faz essa verificação no momento da compilação (definindo uma versão mínima do pacote SDK de Aplicações Windows) ou envolve a chamada em tempo de execução num try/catch — e não com XAML condicional.

Para incluir ou excluir elementos com base na lógica que a sua aplicação define, como um flag de funcionalidade, use uma condição personalizada.

Criar condições personalizadas

A partir do SDK de Aplicações Windows 2.0, podes definir as tuas próprias condições e usá-las com a sintaxe de espaço de nomes condicional. Uma condição personalizada permite-lhe incluir ou excluir marcação com base no estado específico da aplicação, como flags de funcionalidades, definições de configuração ou capacidades do dispositivo. Tal como os métodos condicionais incorporados, as condições personalizadas são avaliadas quando o XAML é analisado em tempo de execução.

Ícone da Galeria WinUI 3 A aplicação WinUI 3 Gallery inclui exemplos interativos de controlos e funcionalidades WinUI. Descarrega a aplicação na Microsoft Store ou navega pelo código-fonte no GitHub.

Note

IXamlConditionsubstitui a IXamlPredicate interface das versões experimentais do SDK de Aplicações Windows 2.0.

Implementar uma condição

Para criar uma condição, defina uma classe que deriva de DependencyObject e implementa IXamlCondition. O analisador XAML chama o método Evaluate e passa o texto entre parênteses da declaração condicional do namespace como parâmetro argument . Selecione true para incluir a marcação qualificada, ou false para ignorá-la.

Este exemplo, do exemplo WinUI 3 Gallery, avalia flags de funcionalidades que a aplicação armazena num dicionário:

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

Declarar um namespace condicional para a condição

Primeiro, mapeie o namespace que contém a sua classe de condição usando uma using: declaração. Depois, após o delimitador ? de um espaço de nomes condicional, referencia-se a classe através desse prefixo e passe o argumento entre parênteses:

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)"

Neste exemplo, o analisador chama Evaluate("NewExperience") para a marcação que usa o prefixo newExp, e Evaluate("LegacyMode") para a marcação que usa o prefixo legacy.

Use a condição nos elementos, atributos e setters

Utilize o prefixo condicional da mesma forma que usa os namespaces condicionais incorporados. Estes exemplos baseiam-se no exemplo da Galeria WinUI 3.

Para incluir um elemento apenas quando uma condição se verificar true, prefixe o elemento:

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

Para definir uma propriedade apenas quando uma condição é true, prefixe o atributo:

<!-- 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" />

Para aplicar um definidor de estilo apenas quando uma condição é true, prefixe o elemento 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>

Defina o estado antes do XAML ser analisado

O analisador armazena em cache o resultado de Evaluate para cada combinação de condição e argumento durante a vida útil do processo. Se mudares o estado que uma condição lê depois de o resultado ser armazenado em cache, a marcação já analisada não muda, e a marcação que é analisada mais tarde continua a usar o resultado em cache. Para usar um valor diferente, reinicie a aplicação.

Defina o estado que a sua condição lê antes de o analisador a avaliar, por exemplo, no arranque da aplicação ou antes de chamar InitializeComponent no construtor de uma página:

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

  • Dois elementos não podem ter o mesmo x:Name, mesmo que apenas um deles esteja incluído em tempo de execução.
  • Se aplicares mais do que uma condição ao mesmo atributo, certifica-te de que só uma delas é avaliada como true em tempo de execução. Se mais do que um for avaliado como true, o analisador lança uma exceção.
  • Como as condições são avaliadas em tempo de execução, o compilador XAML não pode verificá-las quanto à consistência lógica. Testa cada combinação de valores de condição que a tua aplicação suporta.
  • Condições personalizadas não funcionam com itens do x: namespace (http://schemas.microsoft.com/winfx/2006/xaml), como x:Uid e x:Key.