XAML condicional

XAML condicional permite usar el método ApiInformation.IsApiContractPresent directamente en el marcado XAML. Puede establecer propiedades en función de la presencia de un contrato de API de nivel de sistema operativo sin escribir código subyacente. Las instrucciones condicionales se evalúan en tiempo de ejecución: los elementos marcados con una etiqueta XAML condicional se analizan si se evalúan como true y, de lo contrario, se ignoran.

A partir de SDK de Aplicaciones para Windows 2.0, también puede definir sus propias condiciones implementando la interfaz IXamlCondition. Las condiciones personalizadas permiten incluir o excluir el marcado en función del estado específico de la aplicación, como feature flags u opciones de configuración. Para obtener más información, consulta Crear condiciones personalizadas.

XAML condicional requiere Windows 10 versión 1809 (compilación 17763) o posterior, que es la versión mínima del sistema operativo para las aplicaciones de SDK de Aplicaciones para Windows.

Prerequisites

Importante

Los métodos condicionales integrados usan los métodos ApiInformation, que comprueban la presencia de contratos de API y tipos de Windows Runtime (Windows.*) proporcionados por el sistema operativo. Estas comprobaciones no se aplican a los controles de WinUI 3 (Microsoft.UI.Xaml.*), ya que WinUI 3 se distribuye con la aplicación a través de la SDK de Aplicaciones para Windows en lugar de con el sistema operativo, cada control de WinUI 3 en el que se compila la aplicación siempre está presente en tiempo de ejecución, independientemente de la Windows 10/11 compilación en la que se ejecute el dispositivo. #if Las directivas del preprocesador tampoco ayudan aquí: se evalúan en tiempo de compilación en función del marco de destino, no en tiempo de ejecución en función del sistema operativo o de la versión de SDK de Aplicaciones para Windows realmente instalada. Para condicionar una característica a la versión del SDK de aplicaciones de Windows en la que se ejecuta tu aplicación, comprueba la versión del SDK en el momento de la compilación o utiliza un try/catch alrededor de la llamada a la API. Consulte Código adaptable de versión para obtener más información.

Para obtener información general sobre ApiInformation y los contratos de API, consulte Aplicaciones adaptables a versiones.

Espacios de nombres condicionales

Para usar un método condicional en XAML, declare un espacio de nombres XAML condicional en la parte superior de la página:

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

El contenido anterior al ? delimitador es el espacio de nombres o el esquema. El contenido después de ? es el método condicional que determina si el espacio de nombres se evalúa en true o false.

En la mayoría de los casos, el esquema es el espacio de nombres XAML predeterminado:

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

Xaml condicional admite estos métodos condicionales:

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

También puedes usar una condición que definas en la aplicación. Para obtener más información, consulta Crear condiciones personalizadas.

Note

Use IsApiContractPresent y IsApiContractNotPresent para obtener la mejor experiencia en tiempo de diseño. Otros condicionales no se admiten completamente en la experiencia de diseño de Visual Studio.

Establecer una propiedad de forma condicional

Este ejemplo muestra texto en un TextBlock solo cuando la aplicación se ejecuta en Windows 10 versión 1903 (Actualización de mayo de 2019, compilación 18362) o posterior; una comprobación de contrato que tiene sentido porque es más reciente que el mínimo de 1809 del SDK de aplicaciones de Windows.

En primer lugar, defina un espacio de nombres condicional:

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

A continuación, prefijo la propiedad con el espacio de nombres condicional:

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

Aquí está el código de marcado completo:

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

La comprobación equivalente en el código subyacente:

TextBlock textBlock = new TextBlock();

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

Note

Aunque IsApiContractPresent admite una cadena como parámetro de nombre de contrato, no hay que ponerla entre comillas en la declaración del espacio de nombres XAML.

Dado que la versión mínima admitida del sistema operativo de SDK de Aplicaciones para Windows es 1809 (UniversalApiContract versión 7), comprobar una versión de contrato igual o inferior a 7 siempre se evalúa como true en una aplicación de SDK de Aplicaciones para Windows y no proporciona ninguna información útil. Compruebe solo las versiones de contrato superiores a 7.

Utilizar condiciones if/else

Para establecer valores diferentes en función del contrato de API, defina los espacios de nombres condicionales positivos y 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)"

A continuación, establezca la propiedad dos veces, cada una con un prefijo condicional diferente. Solo se aplica una en tiempo de ejecución:

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

Creación de instancias de controles de forma condicional

Note

Crear instancias condicionales de un elemento basado en un contrato de API del sistema operativo, en lugar de establecer condicionalmente una propiedad , es un patrón específico de UWP. No se aplica a los controles WinUI 3.

En UWP, este patrón te permite revertir a un control anterior Windows.UI.Xaml.Controls cuando uno más reciente no estaba disponible en el sistema operativo. En una aplicación de SDK de Aplicaciones para Windows, los controles winUI 3 (Microsoft.UI.Xaml.Controls.*) se envían con la aplicación a través del SDK de Aplicaciones para Windows, no con el sistema operativo. Se garantiza que cada control con el que se compila tu aplicación, incluido ColorPicker, estará presente en tiempo de ejecución, por lo que no es necesario comprobar la versión del sistema operativo antes de instanciarlo.

Si necesitas condicionar un control o una API de WinUI 3 a la versión de SDK de Aplicaciones para Windows a la que va dirigida tu aplicación, realiza esa comprobación en tiempo de compilación (estableciendo como destino una versión mínima del paquete de SDK de Aplicaciones para Windows) o encapsula la llamada en tiempo de ejecución en un try/catch, no con XAML condicional.

Para incluir o excluir elementos en función de la lógica que define la aplicación, como un indicador de función, use una condición personalizada.

Crear condiciones personalizadas

A partir de la versión 2.0 de SDK de Aplicaciones para Windows, puede definir sus propias condiciones y usarlas con la sintaxis del espacio de nombres condicional. Una condición personalizada permite incluir o excluir código de marcado en función del estado específico de la aplicación, como feature flags, opciones de configuración o funcionalidades del dispositivo. Al igual que los métodos condicionales integrados, las condiciones personalizadas se evalúan cuando el XAML se analiza en tiempo de ejecución.

Icono de la galería de WinUI 3 La aplicación Galería de WinUI 3 incluye ejemplos interactivos de características y controles winUI. Obtenga la aplicación desde el Microsoft Store o busque el código fuente en GitHub.

Note

IXamlCondition reemplaza la interfaz IXamlPredicate de las versiones experimentales del SDK de Aplicaciones para Windows 2.0.

Implementar una condición

Para crear una condición, defina una clase que derive de DependencyObject e implemente IXamlCondition. El analizador XAML llama al método Evaluate y pasa el texto entre paréntesis de la declaración de espacio de nombres condicional como parámetro argument . Devuelva true para incluir el marcado calificado o false para omitirlo.

En este ejemplo, del ejemplo de la galería de WinUI 3, se evalúan las marcas de características que la aplicación almacena en un diccionario:

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 un espacio de nombres condicional para la condición

Primero, asigne el espacio de nombres que contiene la clase de condición mediante una declaración using:. A continuación, después del ? delimitador de un espacio de nombres condicional, haga referencia a la clase a través de ese prefijo y pase el argumento entre paréntesis:

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

En este ejemplo, el analizador llama a Evaluate("NewExperience") para el marcado que usa el prefijo newExp y a Evaluate("LegacyMode") para el marcado que usa el prefijo legacy.

Usar la condición en elementos, atributos y setters

Use el prefijo condicional de la misma manera que usa los espacios de nombres condicionales integrados. Estos ejemplos se basan en el ejemplo de la galería de WinUI 3.

Para incluir un elemento solo cuando una condición sea true, coloque un prefijo al 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 establecer una propiedad solo cuando una condición sea true, coloque un prefijo al 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 un setter de estilo solo cuando una condición es true, anteponga el 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>

Establecer el estado antes de analizar el XAML

El analizador almacena en caché el resultado de Evaluate para cada combinación de condición y argumento durante la vigencia del proceso. Si cambia el estado que lee una condición después de almacenar el resultado en caché, el marcado que ya se ha analizado no cambia y el marcado que se analiza más adelante sigue usando el resultado almacenado en caché. Para usar un valor diferente, reinicie la aplicación.

Establezca el estado que la condición lee antes de que el analizador la evalúe, por ejemplo, en el inicio de la aplicación o antes de llamar a InitializeComponent en un constructor 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

  • Dos elementos no pueden tener el mismo x:Name, aunque solo se incluya uno de ellos en tiempo de ejecución.
  • Si aplica más de una condición al mismo atributo, asegúrese de que solo una de ellas se evalúe como true en el entorno de ejecución. Si más de uno se evalúa como true, el analizador produce una excepción.
  • Dado que las condiciones se evalúan en tiempo de ejecución, el compilador XAML no puede comprobar su coherencia lógica. Pruebe cada combinación de valores de condición que admita la aplicación.
  • Las condiciones personalizadas no funcionan con elementos del x: espacio de nombres (http://schemas.microsoft.com/winfx/2006/xaml), como x:Uid y x:Key.