Consumo de extensiones de marcado XAML

Las extensiones de marcado XAML ayudan a mejorar la eficacia y la flexibilidad de XAML al permitir que los atributos de elemento se establezcan desde una variedad de orígenes. Varias extensiones de marcado XAML forman parte de la especificación XAML 2009. Estos aparecen en archivos XAML con el prefijo de espacio de nombres habitual x y se denominan normalmente con este prefijo. En este artículo se describen las siguientes extensiones de marcado:

  • x:Static: referencia a propiedades estáticas, campos o miembros de enumeración.
  • x:Reference: referencia a elementos con nombre en la página.
  • x:Type: establece un atributo en un objeto System.Type.
  • x:Array: crea una matriz de objetos de un tipo determinado.
  • x:Null: establece un atributo en un valor null.
  • OnPlatform: personaliza la apariencia de la interfaz de usuario por plataforma.
  • OnIdiom: personaliza la apariencia de la interfaz de usuario en función de la expresión del dispositivo en el que se ejecuta la aplicación.
  • DataTemplate: convierte un tipo en DataTemplate.
  • FontImage: muestra un icono de fuente en cualquier vista que pueda mostrar un ImageSource.
  • AppThemeBinding: consume un recurso basado en el tema actual del sistema.

Otras implementaciones de XAML admiten históricamente extensiones de marcado XAML adicionales y también son compatibles con Xamarin.Forms. Estos se describen más por completo en otros artículos:

  • StaticResource: hace referencia a objetos de un diccionario de recursos, como se describe en el artículo Diccionarios de recursos.
  • DynamicResource: responde a los cambios en los objetos de un diccionario de recursos, como se describe en el artículo Estilos dinámicos.
  • Binding: establece un vínculo entre las propiedades de dos objetos, como se describe en el artículo Enlace de datos.
  • TemplateBinding: realiza el enlace de datos desde una plantilla de control, como se describe en el artículo Plantillas de control de Xamarin.Forms.
  • RelativeSource: establece el origen de enlace en relación con la posición del destino de enlace, como se describe en el artículo Enlaces relativos.

El diseño RelativeLayout usa la extensión de marcado personalizada ConstraintExpression. Esta extensión de marcado se describe en el artículo RelativeLayout.

Extensión de marcado x:Static

La extensión de marcado x:Static es compatible con la clase StaticExtension. La clase tiene una sola propiedad denominada Member de tipo string que se establece en el nombre de una constante pública, una propiedad estática, un campo estático o un miembro de enumeración.

Una manera común de usar x:Static es definir primero una clase con algunas constantes o variables estáticas, como esta pequeña clase AppConstants:

static class AppConstants
{
    public static double NormalFontSize = 18;
}

En la página x:Demostración estática se muestran varias maneras de usar la extensión de marcado de x:Static. El enfoque más detallado crea una instancia de la clase StaticExtension entre etiquetas de elemento de propiedad Label.FontSize:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:sys="clr-namespace:System;assembly=netstandard"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.StaticDemoPage"
             Title="x:Static Demo">
    <StackLayout Margin="10, 0">
        <Label Text="Label No. 1">
            <Label.FontSize>
                <x:StaticExtension Member="local:AppConstants.NormalFontSize" />
            </Label.FontSize>
        </Label>

        ···

    </StackLayout>
</ContentPage>

El analizador XAML también permite abreviar la clase StaticExtension como x:Static:

<Label Text="Label No. 2">
    <Label.FontSize>
        <x:Static Member="local:AppConstants.NormalFontSize" />
    </Label.FontSize>
</Label>

Esto se puede simplificar aún más, pero el cambio introduce cierta sintaxis nueva: consiste en colocar la clase StaticExtension y el valor de miembro en llaves. La expresión resultante se establece directamente en el atributo FontSize:

<Label Text="Label No. 3"
       FontSize="{x:StaticExtension Member=local:AppConstants.NormalFontSize}" />

Observe que no hay comillas dentro de las llaves. La propiedad Member de StaticExtension ya no es un atributo XML. En su lugar, forma parte de la expresión de la extensión de marcado.

Del mismo modo que puedes abreviar x:StaticExtension a x:Static cuando lo usas como elemento de objeto, también puedes abreviarlo en la expresión entre llaves:

<Label Text="Label No. 4"
       FontSize="{x:Static Member=local:AppConstants.NormalFontSize}" />

La clase StaticExtension tiene un atributo ContentProperty que hace referencia a la propiedad Member, que marca esta propiedad como la propiedad de contenido predeterminada de la clase. Para las extensiones de marcado XAML expresadas con llaves, puedes eliminar la parte Member= de la expresión:

<Label Text="Label No. 5"
       FontSize="{x:Static local:AppConstants.NormalFontSize}" />

Esta es la forma más común de la extensión de marcado x:Static.

La página Demostración estática contiene otros dos ejemplos. La etiqueta raíz del archivo XAML contiene una declaración de espacio de nombres XML para el espacio de nombres de .NET System:

xmlns:sys="clr-namespace:System;assembly=netstandard"

Esto permite establecer el tamaño de fuente Label en el campo estático Math.PI. El resultado es un texto bastante pequeño, por lo que la propiedad Scale se establece en Math.E:

<Label Text="&#x03C0; &#x00D7; E sized text"
       FontSize="{x:Static sys:Math.PI}"
       Scale="{x:Static sys:Math.E}"
       HorizontalOptions="Center" />

En el ejemplo final se muestra el valor de Device.RuntimePlatform. La propiedad estática Environment.NewLine se usa para insertar un carácter de nueva línea entre los dos objetos Span:

<Label HorizontalTextAlignment="Center"
       FontSize="{x:Static local:AppConstants.NormalFontSize}">
    <Label.FormattedText>
        <FormattedString>
            <Span Text="Runtime Platform: " />
            <Span Text="{x:Static sys:Environment.NewLine}" />
            <Span Text="{x:Static Device.RuntimePlatform}" />
        </FormattedString>
    </Label.FormattedText>
</Label>

Este es el ejemplo en ejecución:

Demostración de x:Static

Extensión de marcado x:Reference

La extensión de marcado x:Reference es compatible con la clase ReferenceExtension. La clase tiene una sola propiedad denominada Name de tipo string que se establece en el nombre de un elemento de la página a la que se le ha asignado un nombre con x:Name. Esta propiedad Name es la propiedad de contenido de ReferenceExtension, por lo que Name= no es obligatorio cuando x:Reference aparece entre llaves.

La extensión de marcado x:Reference se usa exclusivamente con enlaces de datos, que se describen con más detalle en el artículo Enlace de datos.

En la página x:Demostración de referencia se muestran dos usos de x:Reference con enlaces de datos, el primero donde se usa para establecer la propiedad Source del objeto Binding y el segundo donde se usa para establecer la propiedad BindingContext para dos enlaces de datos:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ReferenceDemoPage"
             x:Name="page"
             Title="x:Reference Demo">

    <StackLayout Margin="10, 0">

        <Label Text="{Binding Source={x:Reference page},
                              StringFormat='The type of this page is {0}'}"
               FontSize="18"
               VerticalOptions="CenterAndExpand"
               HorizontalTextAlignment="Center" />

        <Slider x:Name="slider"
                Maximum="360"
                VerticalOptions="Center" />

        <Label BindingContext="{x:Reference slider}"
               Text="{Binding Value, StringFormat='{0:F0}&#x00B0; rotation'}"
               Rotation="{Binding Value}"
               FontSize="24"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

    </StackLayout>
</ContentPage>

Ambas expresiones x:Reference usan la versión abreviada del nombre de clase ReferenceExtension y eliminan la parte Name= de la expresión. En el primer ejemplo, la extensión de marcado x:Reference se inserta en la extensión de marcado Binding. Tenga en cuenta que la configuración de Source y StringFormat están separadas por comas. Esta es la ejecución del programa:

Demostración de x:Reference

Extensión de marcado x:Type

La extensión de marcado x:Type es el equivalente en XAML de la palabra clave de C# typeof. Es compatible con la clase TypeExtension, que define una propiedad denominada TypeName de tipo string que se establece en un nombre de clase o estructura. La extensión de marcado x:Type devuelve el objeto System.Type de esa clase o estructura. TypeName es la propiedad de contenido de TypeExtension, por lo que TypeName= no es obligatorio cuando x:Type aparece con llaves.

En Xamarin.Forms, hay varias propiedades que tienen argumentos de tipo Type. Algunos ejemplos incluyen la propiedad TargetType de Style y el atributo x:TypeArguments usado para especificar argumentos en clases genéricas. Sin embargo, el analizador XAML realiza automáticamente la operación de typeof y la extensión de marcado x:Type no se usa en estos casos.

Un lugar donde x:Type es necesario es con la x:Array extensión de marcado, que se describe en la sección siguiente.

La extensión de marcado x:Type también es útil al construir un menú donde cada elemento de menú corresponde a un objeto de un tipo determinado. Puede asociar un objeto Type a cada elemento de menú y, a continuación, crear una instancia del objeto cuando se selecciona el elemento de menú.

Así es como funciona el menú de navegación en MainPage del programa Extensiones de marcado. El archivo MainPage.xaml contiene un TableView con cada TextCell correspondiente a una página determinada del programa:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MarkupExtensions"
             x:Class="MarkupExtensions.MainPage"
             Title="Markup Extensions"
             Padding="10">
    <TableView Intent="Menu">
        <TableRoot>
            <TableSection>
                <TextCell Text="x:Static Demo"
                          Detail="Access constants or statics"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:StaticDemoPage}" />

                <TextCell Text="x:Reference Demo"
                          Detail="Reference named elements on the page"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:ReferenceDemoPage}" />

                <TextCell Text="x:Type Demo"
                          Detail="Associate a Button with a Type"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:TypeDemoPage}" />

                <TextCell Text="x:Array Demo"
                          Detail="Use an array to fill a ListView"
                          Command="{Binding NavigateCommand}"
                          CommandParameter="{x:Type local:ArrayDemoPage}" />

                ···                          

        </TableRoot>
    </TableView>
</ContentPage>

Esta es la página principal de apertura de extensiones de marcado:

Página principal

Cada propiedad CommandParameter se establece en una extensión de marcado x:Type que hace referencia a una de las otras páginas. La propiedad Command está enlazada a una propiedad denominada NavigateCommand. Esta propiedad se define en el archivo de código subyacente MainPage:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        NavigateCommand = new Command<Type>(async (Type pageType) =>
        {
            Page page = (Page)Activator.CreateInstance(pageType);
            await Navigation.PushAsync(page);
        });

        BindingContext = this;
    }

    public ICommand NavigateCommand { private set; get; }
}

La propiedad NavigateCommand es un objeto Command que implementa un comando execute con un argumento de tipo Type, el valor de CommandParameter. El método usa Activator.CreateInstance para crear instancias de la página y, a continuación, navegar a ella. El constructor concluye estableciendo el BindingContext de la página en sí mismo, lo que permite que el Binding en Command funcione. Consulte el artículo Enlace de datos y, especialmente, el artículo Comandos para obtener más información sobre este tipo de código.

La página Demostración x:Type usa una técnica similar para crear instancias de elementos Xamarin.Forms y agregarlos a StackLayout. El archivo XAML consta inicialmente de tres elementos Button con sus propiedades de Command establecidas en un Binding y las propiedades de CommandParameter establecidas en tipos de tres vistas de Xamarin.Forms:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.TypeDemoPage"
             Title="x:Type Demo">

    <StackLayout x:Name="stackLayout"
                 Padding="10, 0">

        <Button Text="Create a Slider"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Slider}" />

        <Button Text="Create a Stepper"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Stepper}" />

        <Button Text="Create a Switch"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Command="{Binding CreateCommand}"
                CommandParameter="{x:Type Switch}" />
    </StackLayout>
</ContentPage>

El archivo de código subyacente define e inicializa la propiedad CreateCommand:

public partial class TypeDemoPage : ContentPage
{
    public TypeDemoPage()
    {
        InitializeComponent();

        CreateCommand = new Command<Type>((Type viewType) =>
        {
            View view = (View)Activator.CreateInstance(viewType);
            view.VerticalOptions = LayoutOptions.CenterAndExpand;
            stackLayout.Children.Add(view);
        });

        BindingContext = this;
    }

    public ICommand CreateCommand { private set; get; }
}

El método que se ejecuta cuando se presiona una Button crea una nueva instancia del argumento, establece su propiedad VerticalOptions y la agrega al StackLayout. A continuación, los tres elementos Button comparten la página con vistas creadas dinámicamente:

Demostración de x:Type

Extensión de marcado x:Array

La extensión de marcado x:Array permite definir una matriz en el marcado. Es compatible con la clase ArrayExtension, que define dos propiedades:

  • Type de tipo Type, que indica el tipo de los elementos de la matriz.
  • Items de tipo IList, que es una colección de los elementos por sí solos. Es la propiedad de contenido de ArrayExtension.

La propia extensión de marcado x:Array nunca aparece entre llaves. En su lugar, las etiquetas start y end x:Array delimitan la lista de elementos. Establezca la propiedad Type en una extensión de marcado x:Type.

La página Demostración x:Array muestra cómo usar x:Array para agregar elementos a ListView mediante el establecimiento de la propiedad ItemsSource en una matriz:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.ArrayDemoPage"
             Title="x:Array Demo Page">
    <ListView Margin="10">
        <ListView.ItemsSource>
            <x:Array Type="{x:Type Color}">
                <Color>Aqua</Color>
                <Color>Black</Color>
                <Color>Blue</Color>
                <Color>Fuchsia</Color>
                <Color>Gray</Color>
                <Color>Green</Color>
                <Color>Lime</Color>
                <Color>Maroon</Color>
                <Color>Navy</Color>
                <Color>Olive</Color>
                <Color>Pink</Color>
                <Color>Purple</Color>
                <Color>Red</Color>
                <Color>Silver</Color>
                <Color>Teal</Color>
                <Color>White</Color>
                <Color>Yellow</Color>
            </x:Array>
        </ListView.ItemsSource>

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <BoxView Color="{Binding}"
                             Margin="3" />    
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>        

ViewCell crea un BoxView simple para cada entrada de color:

Demostración de x:Array

Hay varias maneras de especificar los elementos Color individuales de esta matriz. Puede usar una extensión de marcado x:Static:

<x:Static Member="Color.Blue" />

O bien, puede usar StaticResource para recuperar un color de un diccionario de recursos:

<StaticResource Key="myColor" />

Al final de este artículo, verá una extensión de marcado XAML personalizada que también crea un nuevo valor de color:

<local:HslColor H="0.5" S="1.0" L="0.5" />

Al definir matrices de tipos comunes como cadenas o números, use las etiquetas enumeradas en el artículo Paso de argumentos del constructor para delimitar los valores.

Extensión de marcado x:Null

La clase de marcado x:Null es compatible con la clase NullExtension. No tiene propiedades y es simplemente el equivalente en XAML de la palabra clave de C# null.

La extensión de marcado x:Null rara vez es necesaria y rara vez se usa, pero si encuentra una necesidad para ella, se alegrará de que exista.

En la página Demostración x:Null se muestra un escenario en el que x:Null puede resultar conveniente. Supongamos que define un Style implícito para Label que incluye un Setter que establece la propiedad FontFamily en un nombre de familia dependiente de la plataforma:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.NullDemoPage"
             Title="x:Null Demo">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="48" />
                <Setter Property="FontFamily">
                    <Setter.Value>
                        <OnPlatform x:TypeArguments="x:String">
                            <On Platform="iOS" Value="Times New Roman" />
                            <On Platform="Android" Value="serif" />
                            <On Platform="UWP" Value="Times New Roman" />
                        </OnPlatform>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout Padding="10, 0">
            <Label Text="Text 1" />
            <Label Text="Text 2" />

            <Label Text="Text 3"
                   FontFamily="{x:Null}" />

            <Label Text="Text 4" />
            <Label Text="Text 5" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>   

A continuación, descubre que para uno de los elementos Label, quiere que todos los valores de propiedad del Style implícito, excepto para el FontFamily, que quiere que sea el valor predeterminado. Puede definir otro Style para ese propósito, pero un enfoque más sencillo es simplemente establecer la propiedad FontFamily del Label particular en x:Null, como se muestra en el Label del centro.

Esta es la ejecución del programa:

Demostración de x:Null

Observe que cuatro de los elementos Label tienen una fuente serif, pero el centro Label tiene la fuente sans-serif predeterminada.

Extensión de marcado OnPlatform

La extensión de marcado OnPlatform le permite personalizar el aspecto de la interfaz de usuario para cada plataforma. Ofrece la misma función que las clases OnPlatform y On, pero con una representación más concisa.

La clase OnPlatform admite la extensión de marcado OnPlatformExtension, que define las siguientes propiedades:

  • Default de tipo object, que se establece en un valor predeterminado que se aplicará a las propiedades que representan las plataformas.
  • Android de tipo object, que se establece en un valor que se va a aplicar en Android.
  • GTK de tipo object, que se establece en un valor que se aplicará en plataformas GTK.
  • iOS de tipo object, que se establece en un valor que se va a aplicar en iOS.
  • macOS de tipo object, que se establece en un valor que se aplicará en macOS.
  • Tizen de tipo object, que se establece en un valor que se va a aplicar en la plataforma Tizen.
  • UWP de tipo object, que se establece en un valor que se aplicará en la Plataforma universal de Windows.
  • WPF de tipo object, que se establece en un valor que se aplicará en la plataforma de Windows Presentation Foundation.
  • Converter de tipo IValueConverter, que se puede establecer en una implementación IValueConverter.
  • ConverterParameter de tipo object, que se puede establecer en un valor para pasar a la implementación IValueConverter.

Nota:

El analizador de XAML permite abreviar la clase OnPlatformExtension como OnPlatform.

La propiedad Default es la propiedad de contenido de OnPlatformExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puede eliminar la parte Default= de la expresión, siempre que se trate del primer argumento. Si la propiedad Default no está establecida, se establecerá de forma predeterminada en el valor de la propiedad BindableProperty.DefaultValue, siempre que la extensión de marcado tenga como destino BindableProperty.

Importante

El analizador XAML espera que los valores del tipo correcto se proporcionen a las propiedades que consumen la extensión de marcado OnPlatform. Si es necesaria la conversión de tipos, la extensión de marcado OnPlatform intentará realizarla mediante los convertidores predeterminados proporcionados por Xamarin.Forms. Pero, hay algunas conversiones de tipo que no se pueden realizar en los convertidores predeterminados y, en estos casos, la propiedad Converter debe establecerse en una implementación IValueConverter.

En la página Demostración de OnPlatform se muestra cómo usar la extensión de marcado OnPlatform:

<BoxView Color="{OnPlatform Yellow, iOS=Red, Android=Green, UWP=Blue}"
         WidthRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"  
         HeightRequest="{OnPlatform 250, iOS=200, Android=300, UWP=400}"
         HorizontalOptions="Center" />

En este ejemplo, las tres expresiones OnPlatform usan la versión abreviada del nombre de clase OnPlatformExtension. Las tres extensiones de marcado OnPlatform establecen las propiedades Color, WidthRequest y HeightRequest de BoxView en valores diferentes en iOS, Android y UWP. Las extensiones de marcado también proporcionan valores predeterminados para estas propiedades en las plataformas que no se especifican, al tiempo que se elimina la parte de la expresión Default=. Observe que las propiedades de la extensión de marcado que se establecen están separadas por comas.

Esta es la ejecución del programa:

Demostración de OnPlatform

Extensión de marcado OnIdiom

La extensión de marcado OnIdiom le permite personalizar la apariencia de la interfaz de usuario en función de la expresión del dispositivo en el que se ejecuta la aplicación. La clase OnIdiomExtension admite la extensión de marcado, que define las siguientes propiedades:

  • Default de tipo object, que se establece en un valor predeterminado que se aplicará a las propiedades que representan los tipos de dispositivos.
  • Phone de tipo object, que se establece en un valor que se aplicará en teléfonos.
  • Tablet de tipo object, que se establece en un valor que se va a aplicar en tabletas.
  • Desktop de tipo object, que se establece en un valor que se aplicará en plataformas de escritorio.
  • TV de tipo object, que se establece en un valor que se va a aplicar en las plataformas de TV.
  • Watch de tipo object, que se establece en un valor que se va a aplicar en plataformas de relojes.
  • Converter de tipo IValueConverter, que se puede establecer en una implementación IValueConverter.
  • ConverterParameter de tipo object, que se puede establecer en un valor para pasar a la implementación IValueConverter.

Nota:

El analizador de XAML permite abreviar la clase OnIdiomExtension como OnIdiom.

La propiedad Default es la propiedad de contenido de OnIdiomExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puede eliminar la parte Default= de la expresión, siempre que se trate del primer argumento.

Importante

El analizador XAML espera que los valores del tipo correcto se proporcionen a las propiedades que consumen la extensión de marcado OnIdiom. Si es necesaria la conversión de tipos, la extensión de marcado OnIdiom intentará realizarla mediante los convertidores predeterminados proporcionados por Xamarin.Forms. Pero, hay algunas conversiones de tipo que no se pueden realizar en los convertidores predeterminados y, en estos casos, la propiedad Converter debe establecerse en una implementación IValueConverter.

En la página Demostración de OnIdiom se muestra cómo usar la extensión de marcado OnIdiom:

<BoxView Color="{OnIdiom Yellow, Phone=Red, Tablet=Green, Desktop=Blue}"
         WidthRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
         HeightRequest="{OnIdiom 100, Phone=200, Tablet=300, Desktop=400}"
         HorizontalOptions="Center" />

En este ejemplo, las tres expresiones OnIdiom usan la versión abreviada del nombre de clase OnIdiomExtension. Las tres extensiones de marcadoOnIdiom establecen las propiedades Color, WidthRequest y HeightRequest de BoxView en valores diferentes en las expresiones de teléfono, tableta y escritorio. Las extensiones de marcado también proporcionan valores predeterminados para estas propiedades en las expresiones que no se especifican, al tiempo que se elimina la parte Default= de la expresión. Observe que las propiedades de la extensión de marcado que se establecen están separadas por comas.

Esta es la ejecución del programa:

Demostración de OnIdiom

Extensión de marcado DataTemplate

La extensión de marcado DataTemplate te permite convertir un tipo en DataTemplate. Es compatible con la clase DataTemplateExtension, que define una propiedad TypeName, de tipo string, que se establece en el nombre del tipo que se va a convertir en DataTemplate. La propiedad TypeName es la propiedad de contenido de DataTemplateExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puede eliminar la parte TypeName= de la expresión.

Nota:

El analizador de XAML permite abreviar la clase DataTemplateExtension como DataTemplate.

Una utilización típica de esta extensión de marcado se encuentra en una aplicación de Shell, como se muestra en el ejemplo siguiente:

<ShellContent Title="Monkeys"
              Icon="monkey.png"
              ContentTemplate="{DataTemplate views:MonkeysPage}" />

En este ejemplo, MonkeysPage se convierte de ContentPage a DataTemplate, que se establece como el valor de la propiedad ShellContent.ContentTemplate. Esto garantiza que MonkeysPage solo se crea cuando se navega a la página, no al iniciar la aplicación.

Para más información sobre las aplicaciones de Shell, consulte Xamarin.Forms Shell.

Extensión de marcado FontImage

La extensión de marcado FontImage te permite mostrar un icono de fuente en cualquier vista que pueda mostrar un ImageSource. Proporciona la misma funcionalidad que la clase FontImageSource, pero con una representación más concisa.

La clase FontImage admite la extensión de marcado FontImageExtension, que define las siguientes propiedades:

  • FontFamily de tipo string, la familia de fuentes a la que pertenece el icono de fuente.
  • Glyph de tipo string, el valor de carácter unicode del icono de fuente.
  • Color de tipo Color, el color que se va a usar al mostrar el icono de fuente.
  • Size de tipo double, el tamaño, en unidades independientes del dispositivo, del icono de fuente representado. El valor predeterminado es 30. Además, esta propiedad se puede establecer en un tamaño de fuente con nombre.

Nota:

El analizador de XAML permite abreviar la clase FontImageExtension como FontImage.

La propiedad Glyph es la propiedad de contenido de FontImageExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puedes eliminar la parte Glyph= de la expresión siempre que sea el primer argumento.

La página Demostración de FontImage muestra cómo usar la extensión de marcado FontImage:

<Image BackgroundColor="#D1D1D1"
       Source="{FontImage &#xf30c;, FontFamily={OnPlatform iOS=Ionicons, Android=ionicons.ttf#}, Size=44}" />

En este ejemplo, la versión abreviada del nombre de clase FontImageExtension se usa para mostrar un icono XBox, de la familia de fuentes Ionicons, en un Image. La expresión también usa la extensión de marcado OnPlatform para especificar valores de propiedad FontFamily diferentes en iOS y Android. Además, se elimina la parte Glyph= de la expresión y las propiedades de extensión de marcado que se establecen están separadas por comas. Tenga en cuenta que, aunque el carácter unicode del icono es \uf30c, debe escaparse en XAML y, por tanto, se convierte en &#xf30c;.

Esta es la ejecución del programa:

Captura de pantalla de la extensión de marcado FontImage

Para obtener información sobre cómo mostrar iconos de fuente especificando los datos del icono de fuente en un objeto FontImageSource, consulta Visualización de iconos de fuente.

AppThemeBinding (extensión de marcado)

La extensión de marcado AppThemeBinding permite especificar un recurso que se va a consumir, como una imagen o un color, en función del tema del sistema actual.

Importante

La extensión de marcado AppThemeBinding tiene requisitos mínimos del sistema operativo. Para obtener más información, consulte Responder a los cambios del tema del sistema en las aplicaciones de Xamarin.Forms.

La clase AppThemeBinding admite la extensión de marcado AppThemeBindingExtension, que define las siguientes propiedades:

  • Default, de tipo object, que se establece en el recurso que se va a usar de forma predeterminada.
  • Light, de tipo object, que se establece en el recurso que se va a usar cuando el dispositivo usa su tema claro.
  • Dark, de tipo object, que se establece en el recurso que se va a usar cuando el dispositivo usa su tema oscuro.
  • Value, de tipo object, que devuelve el recurso que está usando actualmente la extensión de marcado.

Nota:

El analizador de XAML permite abreviar la clase AppThemeBindingExtension como AppBindingTheme.

La propiedad Default es la propiedad de contenido de AppThemeBindingExtension. Por lo tanto, para las expresiones de marcado XAML expresadas con llaves, puedes eliminar la parte Default= de la expresión siempre que sea el primer argumento.

En la página Demostración de AppThemeBinding se muestra cómo usar la extensión de marcado AppThemeBinding:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MarkupExtensions.AppThemeBindingDemoPage"
             Title="AppThemeBinding Demo">
    <ContentPage.Resources>

        <Style x:Key="labelStyle"
               TargetType="Label">
            <Setter Property="TextColor"
                    Value="{AppThemeBinding Black, Light=Blue, Dark=Teal}" />
        </Style>

    </ContentPage.Resources>
    <StackLayout Margin="20">
        <Label Text="This text is green in light mode, and red in dark mode."
               TextColor="{AppThemeBinding Light=Green, Dark=Red}" />
        <Label Text="This text is black by default, blue in light mode, and teal in dark mode."
               Style="{StaticResource labelStyle}" />
    </StackLayout>
</ContentPage>

En este ejemplo, el color de texto del primer Label se establece en verde cuando el dispositivo usa su tema claro y se establece en rojo cuando el dispositivo usa su tema oscuro. El segundo Label tiene su propiedad TextColor establecida a través de un Style. Style establece el color de texto de Label en negro de forma predeterminada, en azul cuando el dispositivo usa su tema claro y en verde azulado cuando el dispositivo usa su tema oscuro.

Esta es la ejecución del programa:

Demostración de AppThemeBinding

Definición de extensiones de marcado

Si ha encontrado una necesidad de una extensión de marcado XAML que no está disponible en Xamarin.Forms, puede crear una propia.