XAML condicional

O XAML condicional fornece uma maneira de usar o método ApiInformation.IsApiContractPresent diretamente na marcação XAML. Você pode definir propriedades com base na presença de um contrato de API no nível do sistema operacional sem escrever código atrás. Declarações condicionais são avaliadas em tempo de execução — elementos qualificados com uma tag XAML condicional são analisados se forem avaliados como true e ignorados caso contrário.

A partir do SDK do Aplicativo Windows 2.0, você também pode definir suas próprias condições implementando a interface IXamlCondition. As condições personalizadas permitem incluir ou excluir markup com base no estado específico do aplicativo, como sinalizadores de recurso ou configurações. Para obter mais informações, consulte Criar condições personalizadas.

O XAML condicional requer Windows 10 versão 1809 (build 17763) ou posterior, que é a versão mínima do sistema operacional para aplicativos SDK do Aplicativo Windows.

Pré-requisitos

Importante

Os métodos condicionais integrados utilizam métodos ApiInformation que verificam a presença de contratos de API e tipos do Windows Runtime (Windows.*) fornecidos pelo sistema operacional. Essas verificações não se aplicam a controles WinUI 3 (Microsoft.UI.Xaml.*) porque o WinUI 3 é fornecido com seu aplicativo por meio do SDK do Aplicativo Windows em vez de com o sistema operacional — cada controle WinUI 3 no qual seu aplicativo é criado está sempre presente no runtime, independentemente de qual compilação Windows 10/11 o dispositivo está em execução. #ifAs diretivas de pré-processador também não ajudam aqui: elas são avaliadas em tempo de compilação com base na estrutura de destino, não em runtime com base no sistema operacional ou SDK do Aplicativo Windows versão realmente instalada. Para condicionar um recurso na versão do SDK do Aplicativo Windows na qual o aplicativo está sendo executado, verifique a versão do SDK no momento de criar ou use um bloco try/catch na chamada à API. Consulte o código adaptável de versão para obter detalhes.

Para obter informações básicas sobre ApiInformation e contratos de API, consulte Aplicativos adaptáveis à versão.

Namespaces condicionais

Para usar um método condicional em XAML, declare um namespace XAML condicional na parte superior da 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 é avaliado como true ou false.

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

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

O XAML condicional dá suporte a esses métodos condicionais:

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

Você também pode usar uma condição que você define em seu aplicativo. Para obter mais informações, consulte Criar condições personalizadas.

Note

Use IsApiContractPresent e IsApiContractNotPresent para obter a melhor experiência do tempo de design. Não há suporte total para outras condicionalidades na experiência de design Visual Studio.

Definir uma propriedade condicionalmente

Este exemplo só exibe texto em um TextBlock quando o aplicativo é executado no Windows 10 versão 1903 (Atualização de maio de 2019, build 18362) ou posterior – uma verificação de contrato que é significativa porque é mais recente do que o piso 1809 do SDK do Aplicativo Windows.

Primeiro, defina um namespace condicional:

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

Em seguida, prefixe a propriedade com o namespace condicional:

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

Aqui está a marcação 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 atrás:

TextBlock textBlock = new TextBlock();

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

Note

Embora IsApiContractPresent aceite uma string para o parâmetro de nome do contrato, você não deve colocá-lo entre aspas na declaração de namespace XAML.

Como a versão mínima com suporte do sistema operacional para o SDK do Aplicativo Windows é 1809 (UniversalApiContract versão 7), verificar uma versão de contrato igual ou inferior a 7 em um aplicativo do SDK do Aplicativo Windows sempre é avaliada como true e não fornece nenhuma informação útil. Verifique apenas se há versões de contrato superiores a 7.

Usar as condições if/else

Para definir valores diferentes dependendo do contrato de API, defina os namespaces condicionais positivos e negativos:

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

Em seguida, defina a propriedade duas vezes, cada uma com um prefixo condicional diferente. Somente um é aplicado no runtime:

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

Instanciar controles condicionalmente

Note

A instanciação condicional de um elemento com base em um contrato de API do sistema operacional , em vez de definir condicionalmente uma propriedade , é um padrão específico da UWP. Ele não se aplica aos controles WinUI 3.

Na UWP, esse padrão permite que você volte para um controle mais antigo Windows.UI.Xaml.Controls quando um mais novo não estava disponível no sistema operacional. Em um aplicativo SDK do Aplicativo Windows, os controles winui 3 (Microsoft.UI.Xaml.Controls.*) são enviados com seu aplicativo por meio do SDK do Aplicativo Windows, não com o sistema operacional. Todos os controles com os quais seu aplicativo é criado, inclusive ColorPicker , têm a garantia de estar presente no runtime, portanto, não há nenhuma versão do sistema operacional para verificar antes de instanciá-lo.

Se você precisar condicionar um controle ou uma API do WinUI 3 à versão do SDK do Aplicativo Windows que seu aplicativo tem como destino, faça essa verificação em tempo de compilação (definindo como destino uma versão mínima do pacote do SDK do Aplicativo Windows) ou encapsule a chamada em tempo de execução em um try/catch — não com XAML condicional.

Para incluir ou excluir elementos com base na lógica que seu aplicativo define, como um sinalizador de recurso, use uma condição personalizada.

Criar condições personalizadas

A partir do SDK do Aplicativo Windows 2.0, você pode definir suas próprias condições e usá-las com a sintaxe do namespace condicional. Uma condição personalizada permite incluir ou excluir marcação com base no estado específico do aplicativo, como sinalizadores de recursos, configurações ou capacidades do dispositivo. Assim como os métodos condicionais internos, as condições personalizadas são avaliadas quando o XAML é analisado em runtime.

Ícone da Galeria do WinUI 3 O aplicativo Da Galeria do WinUI 3 inclui exemplos interativos de controles e recursos do WinUI. Obtenha o aplicativo na Microsoft Store ou navegue pelo código-fonte em GitHub.

Note

IXamlConditionsubstitui a IXamlPredicate interface de versões experimentais do SDK do Aplicativo Windows 2.0.

Implementar uma condição

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

Este exemplo, do exemplo Galeria do WinUI 3, avalia os sinalizadores de recursos que o aplicativo armazena em um 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 sua classe de condição usando uma using: declaração. Em seguida, após o ? delimitador de um namespace condicional, faça referência à classe por meio 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") a marcação que usa o newExp prefixo e Evaluate("LegacyMode") para a marcação que usa o legacy prefixo.

Aplicar a condição a elementos, atributos e setters

Use o prefixo condicional da mesma forma que você utiliza os namespaces condicionais nativos. Esses exemplos são baseados no exemplo da Galeria do WinUI 3.

Para incluir um elemento somente quando uma condição for 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 somente quando uma condição for 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 setter de estilo somente quando uma condição for true, prefixe o Setter elemento:

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

Definir o estado antes que o XAML seja analisado

O analisador armazena em cache o resultado de Evaluate para cada combinação de condição e argumento durante o tempo de vida do processo. Se você alterar o estado que uma condição lê após o resultado ser armazenado em cache, a marcação que já foi analisada não será alterada e a marcação analisada posteriormente ainda usará o resultado armazenado em cache. Para usar um valor diferente, reinicie o aplicativo.

Defina o estado que sua condição lê antes que o analisador o avalie, por exemplo, na inicialização do aplicativo ou antes de chamar InitializeComponent em um construtor de 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 no runtime.
  • Se você aplicar mais de uma condição ao mesmo atributo, verifique se apenas uma delas é avaliada como true em runtime. Se mais de um resultar em true, o analisador lançará uma exceção.
  • Como as condições são avaliadas em runtime, o compilador XAML não pode verificá-las quanto à consistência lógica. Teste cada combinação de valores de condição que seu aplicativo suporta.
  • As condições personalizadas não funcionam com itens do x: namespace (http://schemas.microsoft.com/winfx/2006/xaml), como x:Uid e x:Key.