Compartir vía


XAML condicional

El XAML condicional ofrece una manera de usar el método ApiInformation.IsApiContractPresent en el marcado XAML. Esto te permite establecer las propiedades y crear instancias de objetos en el marcado en función de la presencia de una API, sin tener que usar código subyacente. Analiza selectivamente elementos o atributos para determinar si estarán disponibles en el tiempo de ejecución. Las instrucciones condicionales se evalúan en el tiempo de ejecución, y los elementos calificados con una etiqueta de XAML condicional se analizan si se evalúan como true; de lo contrario, se ignoran.

El XAML condicional está disponible a partir de la actualización Creators Update (versión 1703, compilación 15063). Para usar XAML condicional, la versión mínima de tu proyecto de Visual Studio debe establecerse en la compilación 15063 (Creators Update) o posterior, y configurar la versión de destino en una versión posterior a la versión mínima. Consulta Aplicaciones adaptables para versiones para obtener más información acerca de cómo configurar el proyecto de Visual Studio.

Nota

Para crear una versión de la aplicación adaptable para versiones con una versión mínima menor que la compilación 15063, debes usar código adaptable para versiones y no XAML.

Para obtener más información general acerca de ApiInformation y contratos de API, consulta Aplicaciones adaptables para versiones.

Espacios de nombres condicionales

Para usar un método condicional en XAML, primero debes declarar un espacio de nombres XAML condicional en la parte superior de la página. Este es un ejemplo de seudocódigo de un espacio de nombres condicional:

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

Un espacio de nombres condicional se puede dividir en dos partes separadas por el delimitador "?".

  • El contenido que precede al delimitador indica el espacio de nombres o el esquema que contiene la API a la que se hace referencia.
  • El contenido después del delimitador "?" representa el método condicional que determina si el espacio de nombres condicional se evalúa como true o false.

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

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

El XAML condicional es compatible con los siguientes métodos condicionales:

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

Comentaremos estos métodos en más profundidad en secciones posteriores de este artículo.

Nota

Te recomendamos que uses IsApiContractPresent e IsApiContractNotPresent. Otras elementos condicionales no son totalmente compatibles con la experiencia de diseño de Visual Studio.

Crear un espacio de nombres y establecer una propiedad

En este ejemplo, se mostrará "Hello, Conditional XAML" como el contenido de un bloque de texto si la aplicación se ejecuta en la versión Fall Creators Update o una versión posterior, y de forma predeterminada no se mostrará ningún contenido si se trata de una versión anterior.

En primer lugar, defina un espacio de nombres personalizado con el prefijo "contract5Present" y use el espacio de nombres XAML predeterminado (https://schemas.microsoft.com/winfx/2006/xaml/presentation) como el esquema que contiene la propiedad TextBlock.Text. Para hacer que sea un espacio de nombres condicional, agrega el delimitador "?" después del esquema.

A continuación define una instrucción condicional que devuelva true en dispositivos que ejecuten la versión Fall Creators Update o una versión posterior. Usa el método ApiInformation IsApiContractPresent para probar la versión 5 de UniversalApiContract. La versión 5 de UniversalApiContract se publicó con la versión Fall Creators Update (SDK 16299).

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

Después de definir el espacio de nombres, antepón el prefijo del espacio de nombres a la propiedad Text de tu control TextBox para que exista una propiedad que se debe establecer condicionalmente en tiempo de ejecución.

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

Este el código XAML 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: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>

Cuando ejecutas este ejemplo en la versión Fall Creators Update, se muestra el texto: "Hello, Conditional XAML". Cuando se ejecuta en la versión Creators Update, no se muestra ningún texto.

El XAML condicional te permite realizar en el marcado las comprobaciones de API que puedes hacer en el código. Este es el código equivalente de esta comprobación.

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

Recuerda que aunque el método IsApiContractPresent toma una cadena el parámetro contractName no colocarás las comillas (" ") en la declaración de espacio de nombres XAML.

Usar condiciones if/else

En el ejemplo anterior, la propiedad Text solo se establece cuando la aplicación se ejecuta en la versión Fall Creators Update. Pero, ¿qué ocurre si quieres mostrar texto diferente al ejecutarla en la versión Creators Update? Podrías intentar establecer la propiedad Text sin ningún calificador condicional, así.

<!-- DO NOT USE -->
<TextBlock Text="Hello, World" contract5Present:Text="Hello, Conditional XAML"/>

Esto funcionaría si se ejecuta en la versión Creators Update, pero si se ejecuta en la versión Fall Creators Update, recibirás un mensaje de error diciendo que la propiedad Text se ha establecido más de una vez.

Para configurar texto diferente cuando la aplicación se ejecute en diferentes versiones de Windows 10, necesitas otra condición. El código XAML condicional proporciona una versión inversa de cada método ApiInformation compatible para que puedas crear escenarios condicionales con if/else como este.

El método IsApiContractPresent devuelve true si el dispositivo actual contiene el número de contrato y la versión especificados. Por ejemplo, supongamos que la aplicación se ejecuta en la versión Creators Update, que tiene la versión 4 del contrato de API universal.

Las distintas llamadas a IsApiContractPresent darían estos resultados:

  • 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 devuelve la inversa de IsApiContractPresent. Las llamadas a IsApiContractNotPresent darían estos resultados:

  • 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

Para usar la condición inversa, crea un segundo espacio de nombres XAML condicional que use la instrucción condicional IsApiContractNotPresent. Aquí, tiene el prefijo "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)"

Con los dos espacios de nombres definidos, puedes establecer la propiedad Text dos veces siempre y cuando uses en ellos el prefijo con los calificadores que aseguren que solo se use una configuración de propiedades en tiempo de ejecución, de esta manera:

<TextBlock contract5NotPresent:Text="Hello, World"
           contract5Present:Text="Hello, Fall Creators Update"/>

Este es otro ejemplo que establece el fondo de un botón. La característica de material acrílico está disponible a partir de la versión Fall Creators Update, así que usaremos Acrylic para el fondo cuando la aplicación se ejecute en Fall Creators Update. No está disponible en versiones anteriores, por lo que en estos casos, el fondo será de color rojo.

<Button Content="Button"
        contract5NotPresent:Background="Red"
        contract5Present:Background="{ThemeResource SystemControlAcrylicElementBrush}"/>

Crear controles y enlazar propiedades

Hasta ahora, has visto cómo establecer propiedades con XAML condicional, pero también puedes crear condicionalmente instancias de controles basados en el contrato de API, disponible en tiempo de ejecución.

Aquí se crea una instancia de un control ColorPicker cuando la aplicación se ejecuta en la versión Fall Creators Update, donde el control está disponible. ColorPicker no está disponible en versiones anteriores a Fall Creators Update, por lo que cuando la aplicación se ejecuta en ellas, tienes que emplear ComboBox para proporcionar al usuario opciones de color simplificadas.

<contract5Present:ColorPicker x:Name="colorPicker"
                              Grid.Column="1"
                              VerticalAlignment="Center"/>

<contract5NotPresent:ComboBox x:Name="colorComboBox"
                              PlaceholderText="Pick a color"
                              Grid.Column="1"
                              VerticalAlignment="Center">

Puedes usar calificadores condicionales con distintas formas de sintaxis de propiedad XAML. Aquí, la propiedad Fill del rectángulo se establece usando la sintaxis de elemento de propiedad para la versión Fall Creators Update y la sintaxis de atributo para las versiones anteriores.

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

Al enlazar una propiedad con otra propiedad que dependa de un espacio de nombres condicional, debes usar la misma condición en ambas propiedades. Aquí, colorPicker.Color depende del espacio de nombres condicional "contract5Present", por lo que también se debe colocar el prefijo "contract5Present" en la propiedad SolidColorBrush.Color. (O también puedes colocar el prefijo "contract5Present" en SolidColorBrush en lugar de en la propiedad Color). Si no lo haces, obtendrás un error en el tiempo de compilación.

<SolidColorBrush contract5Present:Color="{x:Bind colorPicker.Color, Mode=OneWay}"/>

Este es el código XAML completo que demuestra estos escenarios. Este ejemplo contiene un rectángulo y una interfaz de usuario que te permite establecer el color del rectángulo.

Si la aplicación se ejecuta en la versión Fall Creators Update, usa ColorPicker para permitir al usuario establecer el color. ColorPicker no está disponible en versiones anteriores a Fall Creators Update, por lo que cuando la aplicación se ejecuta en estas versiones anteriores, tienes que emplear un cuadro combinado para proporcionar al usuario opciones de color simplificadas.

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