Sintaxis XAML esencial

Browse sample.Examina la muestra

XAML está diseñado principalmente para crear instancias e inicializar objetos. Pero a menudo, las propiedades deben establecerse en objetos complejos que no se pueden representar fácilmente como cadenas XML y, a veces, las propiedades definidas por una clase deben establecerse en una clase secundaria. Estas dos necesidades requieren las características esenciales de sintaxis XAML de elementos de propiedad y propiedades adjuntas.

Elementos de propiedad

En XAML de la interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI), las propiedades de las clases se establecen normalmente como atributos XML:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="18"
       TextColor="Aqua" />

Sin embargo, hay una manera alternativa de establecer una propiedad en XAML:

<Label Text="Hello, XAML!"
       VerticalOptions="Center"
       FontAttributes="Bold"
       FontSize="18">
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>

Estos dos ejemplos que especifican la propiedad TextColor son funcionalmente equivalentes y permiten introducir cierta terminología básica:

  • Label es un elemento de objeto. Es un objeto .NET MAUI expresado como un elemento XML.
  • Text, FontAttributes, VerticalOptions y FontSize son atributos de propiedad. Son propiedades de .NET MAUI expresadas como atributos XML.
  • En el segundo ejemplo, TextColor se ha convertido en un elemento de propiedad. Es una propiedad de .NET MAUI expresada como un elemento XML.

Nota:

En un elemento de propiedad, el valor de la propiedad siempre se define como el contenido entre las etiquetas start y end de property-element.

La sintaxis del elemento de property-element también se puede usar en más de una propiedad de un objeto:

<Label Text="Hello, XAML!"
       VerticalOptions="Center">
    <Label.FontAttributes>
        Bold
    </Label.FontAttributes>
    <Label.FontSize>
        Large
    </Label.FontSize>
    <Label.TextColor>
        Aqua
    </Label.TextColor>
</Label>

Aunque la sintaxis de property-element puede parecer innecesaria, es esencial cuando el valor de una propiedad sea demasiado complejo para expresarse con una cadena simple. Dentro de las etiquetas de property-element, puedes crear una instancia de otro objeto y establecer sus propiedades. Por ejemplo, el diseño Grid tiene propiedades denominadas RowDefinitions y ColumnDefinitions, que son de tipo RowDefinitionCollection y ColumnDefinitionCollection respectivamente. Estos tipos son colecciones de objetos RowDefinition y ColumnDefinition, y normalmente se utiliza la sintaxis de elementos de propiedad para establecerlos:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>
        ...
    </Grid>
</ContentPage>

Propiedades adjuntas

En el ejemplo anterior has visto que Grid requiere elementos de propiedad para las colecciones RowDefinitions y ColumnDefinitions para definir las filas y columnas. Esto sugiere que debe haber una técnica para indicar la fila y la columna donde reside cada elemento secundario de Grid.

Dentro de la etiqueta para cada elemento secundario de Grid se especifica la fila y la columna de ese elemento secundario utilizando los atributos Grid.Row y Grid.Column, que tienen valores predeterminados de 0. También puedes indicar si un elemento secundario abarca más de una fila o columna con los atributos Grid.RowSpan y Grid.ColumnSpan, cuyos valores predeterminados son 1.

En el siguiente ejemplo se muestra la colocación de los elementos secundarios dentro de Grid:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.GridDemoPage"
             Title="Grid Demo Page">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
        </Grid.ColumnDefinitions>

        <Label Text="Autosized cell"
               TextColor="White"
               BackgroundColor="Blue" />
        <BoxView Color="Silver"
                 Grid.Column="1" />
        <BoxView Color="Teal"
                 Grid.Row="1" />
        <Label Text="Leftover space"
               Grid.Row="1" Grid.Column="1"
               TextColor="Purple"
               BackgroundColor="Aqua"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />
        <Label Text="Span two rows (or more if you want)"
               Grid.Column="2" Grid.RowSpan="2"
               TextColor="Yellow"
               BackgroundColor="Blue"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />
        <Label Text="Span two columns"
               Grid.Row="2" Grid.ColumnSpan="2"
               TextColor="Blue"
               BackgroundColor="Yellow"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />
        <Label Text="Fixed 100x100"
               Grid.Row="2" Grid.Column="2"
               TextColor="Aqua"
               BackgroundColor="Red"
               HorizontalTextAlignment="Center"
               VerticalTextAlignment="Center" />

    </Grid>
</ContentPage>

Este XAML da como resultado el siguiente diseño flotante:

.NET MAUI Grid layout.

Los atributos Grid.Row, Grid.Column, Grid.RowSpan y Grid.ColumnSpan parecen ser propiedades de la clase Grid, pero esta clase no define nada denominado Row, Column, RowSpan o ColumnSpan. En su lugar, la clase Grid define cuatro propiedades enlazables denominadas RowProperty, ColumnProperty, RowSpanProperty y ColumnSpanProperty, que son tipos especiales de propiedades enlazables conocidas como propiedades adjuntas. Las define la clase Grid, pero se establecen en los elementos secundarios de Grid.

Nota:

Cuando quieras usar estas propiedades adjuntas en código, la clase Grid proporciona métodos estáticos denominados GetRow, SetRow, GetColumn, SetColumn, GetRowSpan, SetRowSpan, GetColumnSpan y SetColumnSpan.

Las propiedades adjuntas se reconocen en XAML como atributos que contienen una clase y un nombre de propiedad separados por un punto. Se denominan propiedades adjuntas porque están definidas por una clase (en este caso, Grid), pero adjuntas a otros objetos (en este caso, elementos secundarios de Grid). Durante el diseño, Grid puede consultar los valores de estas propiedades adjuntas para saber dónde colocar cada elemento secundario.

Propiedades de contenido

En el ejemplo anterior, se establece la propiedad Content de ContentPage en el objeto Grid. Sin embargo, no se ha hecho referencia a la propiedad Content en XAML, pero puede hacerse:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <ContentPage.Content>
        <Grid>
            ...
        </Grid>
    </ContentPage.Content>
</ContentPage>

La propiedad Content no es obligatoria en XAML porque a los elementos definidos para su uso en .NET MAUI XAML se les permite tener una propiedad especificada como atributo ContentProperty en la clase:

[ContentProperty("Content")]
public class ContentPage : TemplatedPage
{
    ...
}

Cualquier propiedad especificada como ContentProperty de una clase significa que las etiquetas property-element para la propiedad no son obligatorias. Por lo tanto, el ejemplo anterior especifica que cualquier contenido XAML que aparezca entre las etiquetas ContentPage start y end se asigna a la propiedad Content.

Muchas clases también tienen definiciones de atributo ContentProperty. Por ejemplo, la propiedad de contenido de Label es Text.

Diferencias entre plataformas

Las aplicaciones de .NET MAUI pueden personalizar la apariencia de la interfaz de usuario por plataforma. Esto se puede lograr en XAML mediante las clases OnPlatform y On:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness">
            <On Platform="iOS" Value="0,20,0,0" />
            <On Platform="Android" Value="10,20,20,10" />
        </OnPlatform>
    </ContentPage.Padding>
    ...
</ContentPage>

OnPlatform es una clase genérica y, por tanto, debes especificar el argumento de tipo genérico, en este caso, Thickness, que es el tipo de propiedad Padding. Esto se logra con el atributo x:TypeArguments de XAML. La clase OnPlatform define una propiedad Default que se puede establecer en un valor que se aplicará a todas las plataformas:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" Default="20">
            <On Platform="iOS" Value="0,20,0,0" />
            <On Platform="Android" Value="10,20,20,10" />
        </OnPlatform>
    </ContentPage.Padding>
    ...
</ContentPage>

En este ejemplo, la propiedad Padding se establece en valores diferentes en iOS y Android, mientras que en las demás plataformas se establece en el valor predeterminado.

La clase OnPlatform también define una propiedad Platforms, que es un objeto IList de objetos On. Cada objeto On puede establecer Platform y la propiedad Value para definir el valor Thickness de una plataforma específica. Además, la propiedad Platform de On es de tipo IList<string>, por lo que puedes incluir varias plataformas si los valores son los mismos:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="...">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" Default="20">
            <On Platform="iOS, Android" Value="10,20,20,10" />
        </OnPlatform>
    </ContentPage.Padding>
    ...
</ContentPage>

Esta es la manera estándar de establecer una propiedad Padding dependiente de la plataforma en XAML.

Nota:

Si la propiedad Value de un objeto On no se puede representar mediante una sola cadena, puedes definir elementos de propiedad para él.

Para obtener más información, consulta Personalización de la apariencia de la interfaz de usuario en función de la plataforma.

Pasos siguientes

Las extensiones de marcado de .NET MAUI XAML permiten establecer propiedades en objetos o valores a los que se hace referencia indirectamente desde otros orígenes. Las extensiones de marcado XAML son especialmente importantes para compartir objetos y hacer referencia a constantes usadas en toda una aplicación.