Parte 1. Introducción a XAML

Descargar ejemploDescargar el ejemplo

En una Xamarin.Forms aplicación, XAML se usa principalmente para definir el contenido visual de una página y funciona junto con un archivo de código subyacente de C#.

El archivo de código subyacente proporciona compatibilidad con código para el marcado. Juntos, estos dos archivos contribuyen a una nueva definición de clase que incluye vistas secundarias e inicialización de propiedades. Dentro del archivo XAML, se hace referencia a clases y propiedades con elementos y atributos XML, y se establecen vínculos entre el marcado y el código.

Crear la solución

Para empezar a editar el primer archivo XAML, use Visual Studio o Visual Studio para Mac para crear una nueva Xamarin.Forms solución. (Seleccione la pestaña siguiente correspondiente a su entorno).

En Windows, inicie Visual Studio 2019 y, en la ventana de inicio, haga clic en Crear un nuevo proyecto para crear un nuevo proyecto:

Ventana Nueva solución

En la ventana Crear un proyecto nuevo, seleccione Móvil en la lista desplegable Tipo de proyecto, elija la plantilla Aplicación móvil (Xamarin.Forms) y haga clic en el botón Siguiente:

Ventana Nuevo proyecto

En la ventana Configurar el nuevo proyecto , establezca el nombre del proyecto en XamlSamples (o lo que prefiera) y haga clic en el botón Crear .

En el cuadro de diálogo Nueva aplicación multiplataforma , haga clic en En blanco y haga clic en el botón Aceptar :

Cuadro de diálogo Nueva aplicación

Se crean cuatro proyectos en la solución: la biblioteca XamlSamples .NET Standard, XamlSamples.Android, XamlSamples.iOS y la solución Plataforma universal de Windows, XamlSamples.UWP.

Después de crear la solución XamlSamples , es posible que quiera probar el entorno de desarrollo seleccionando los distintos proyectos de plataforma como proyecto de inicio de la solución, y compilando e implementando la aplicación sencilla creada por la plantilla de proyecto en emuladores de teléfono o dispositivos reales.

A menos que necesites escribir código específico de la plataforma, el proyecto de biblioteca xamlSamples compartido de .NET Standard es donde gastarás prácticamente todo el tiempo de programación. Estos artículos no se aventurarán fuera de ese proyecto.

Anatomía de un archivo XAML

Dentro de la biblioteca XamlSamples .NET Standard hay un par de archivos con los nombres siguientes:

  • App.xaml, el archivo XAML; Y
  • App.xaml.cs, un archivo de código subyacente de C# asociado al archivo XAML.

Tendrás que hacer clic en la flecha situada junto a App.xaml para ver el archivo de código subyacente.

Tanto App.xaml como App.xaml.cs contribuyen a una clase denominada App que deriva de Application. La mayoría de las demás clases con archivos XAML contribuyen a una clase que deriva de ContentPage; esos archivos usan XAML para definir el contenido visual de una página completa. Esto es cierto en los otros dos archivos del proyecto XamlSamples :

  • MainPage.xaml, el archivo XAML; Y
  • MainPage.xaml.cs, el archivo de código subyacente de C#.

El archivo MainPage.xaml tiene este aspecto (aunque el formato puede ser un poco diferente):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:XamlSamples"
             x:Class="XamlSamples.MainPage">

    <StackLayout>
        <!-- Place new controls here -->
        <Label Text="Welcome to Xamarin Forms!"
               VerticalOptions="Center"
               HorizontalOptions="Center" />
    </StackLayout>

</ContentPage>

Las dos declaraciones de espacio de nombres XML (xmlns) hacen referencia a URI, la primera aparentemente en el sitio web de Xamarin y la segunda en Microsoft. No te moleste en comprobar a qué apuntan esos URI. No hay nada ahí. Son simplemente URI propiedad de Xamarin y Microsoft, y básicamente funcionan como identificadores de versión.

La primera declaración de espacio de nombres XML significa que las etiquetas definidas en el archivo XAML sin prefijo hacen referencia a clases de Xamarin.Forms, por ejemplo ContentPage. La segunda declaración de espacio de nombres define un prefijo de x. Esto se usa para varios elementos y atributos que son intrínsecos a XAML y que son compatibles con otras implementaciones de XAML. Sin embargo, estos elementos y atributos son ligeramente diferentes en función del año incrustado en el URI. Xamarin.Forms admite la especificación XAML 2009, pero no todas.

La local declaración de espacio de nombres permite tener acceso a otras clases desde el proyecto de biblioteca de .NET Standard.

Al final de esa primera etiqueta, el x prefijo se usa para un atributo denominado Class. Dado que el uso de este x prefijo es prácticamente universal para el espacio de nombres XAML, los atributos XAML, como Class casi siempre se conocen como x:Class.

El x:Class atributo especifica un nombre de clase .NET completo: la MainPage clase del XamlSamples espacio de nombres . Esto significa que este archivo XAML define una nueva clase denominada MainPage en el XamlSamples espacio de nombres que deriva de ContentPage: la etiqueta en la que aparece el x:Class atributo.

El x:Class atributo solo puede aparecer en el elemento raíz de un archivo XAML para definir una clase de C# derivada. Esta es la única clase nueva definida en el archivo XAML. En su lugar, todo lo demás que aparece en el archivo XAML se crea una instancia de las clases existentes e inicializa.

El archivo MainPage.xaml.cs tiene este aspecto (aparte de las directivas sin usar using ):

using Xamarin.Forms;

namespace XamlSamples
{
    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    }
}

La MainPage clase deriva de ContentPage, pero observe la definición de clase partial . Esto sugiere que debe haber otra definición de clase parcial para MainPage, pero ¿dónde está? ¿Y qué es ese InitializeComponent método?

Cuando Visual Studio compila el proyecto, analiza el archivo XAML para generar un archivo de código de C#. Si observas en el directorio XamlSamples\XamlSamples\obj\Debug , encontrarás un archivo denominado XamlSamples.MainPage.xaml.g.cs. El valor 'g' significa generado. Esta es la otra definición de clase parcial de MainPage que contiene la definición del InitializeComponent método al que se llama desde el MainPage constructor. Estas dos definiciones de clase parcial MainPage se pueden compilar juntas. Dependiendo de si el XAML se compila o no, el archivo XAML o una forma binaria del archivo XAML se inserta en el archivo ejecutable.

En tiempo de ejecución, el código del proyecto de plataforma concreto llama a un LoadApplication método y lo pasa a una nueva instancia de la App clase en la biblioteca de .NET Standard. El App constructor de clase crea una MainPageinstancia de . El constructor de esa clase llama a , que a continuación llama InitializeComponental LoadFromXaml método que extrae el archivo XAML (o su binario compilado) de la biblioteca de .NET Standard. LoadFromXaml inicializa todos los objetos definidos en el archivo XAML, los conecta todos juntos en relaciones de elementos primarios y secundarios, adjunta controladores de eventos definidos en el código a eventos establecidos en el archivo XAML y establece el árbol resultante de objetos como contenido de la página.

Aunque normalmente no es necesario dedicar mucho tiempo a los archivos de código generados, a veces se generan excepciones en tiempo de ejecución en el código de los archivos generados, por lo que debe estar familiarizado con ellos.

Al compilar y ejecutar este programa, el Label elemento aparece en el centro de la página, como sugiere XAML:

Pantalla predeterminada Xamarin.Forms

Para objetos visuales más interesantes, todo lo que necesitas es xaml más interesante.

Agregar nuevas páginas XAML

Para agregar otras clases basadas en ContentPage XAML al proyecto, seleccione el proyecto de biblioteca XamlSamples .NET Standard, haga clic con el botón derecho y seleccione Agregar > nuevo elemento.... En el cuadro de diálogo Agregar nuevo elemento , seleccione Página de contenido de elementos >Xamarin.Forms> de Visual C# (no página de contenido (C#), que crea una página de solo código o una vista de contenido, que no es una página). Asigne un nombre a la página, por ejemplo , HelloXamlPage:

Cuadro de diálogo Agregar nuevo elemento

Se agregan dos archivos al proyecto , HelloXamlPage.xaml y el archivo de código subyacente HelloXamlPage.xaml.cs.

Establecer contenido de página

Edite el archivo HelloXamlPage.xaml para que las únicas etiquetas sean para ContentPage y ContentPage.Content:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage">
    <ContentPage.Content>

    </ContentPage.Content>
</ContentPage>

Las ContentPage.Content etiquetas forman parte de la sintaxis única de XAML. Al principio, podrían parecer xml no válidos, pero son legales. El punto no es un carácter especial en XML.

Las ContentPage.Content etiquetas se denominan etiquetas de elemento de propiedad . Content es una propiedad de ContentPagey, por lo general, se establece en una sola vista o un diseño con vistas secundarias. Normalmente, las propiedades se convierten en atributos en XAML, pero sería difícil establecer un Content atributo en un objeto complejo. Por ese motivo, la propiedad se expresa como un elemento XML que consta del nombre de clase y el nombre de propiedad separados por un punto. Ahora la Content propiedad se puede establecer entre las ContentPage.Content etiquetas, como esta:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.HelloXamlPage"
             Title="Hello XAML Page">
    <ContentPage.Content>

        <Label Text="Hello, XAML!"
               VerticalOptions="Center"
               HorizontalTextAlignment="Center"
               Rotation="-15"
               IsVisible="true"
               FontSize="Large"
               FontAttributes="Bold"
               TextColor="Blue" />

    </ContentPage.Content>
</ContentPage>

Observe también que se ha establecido un Title atributo en la etiqueta raíz.

En este momento, la relación entre clases, propiedades y XML debe ser evidente: una Xamarin.Forms clase (como ContentPage o Label) aparece en el archivo XAML como un elemento XML. Las propiedades de esa clase, incluidas Title las propiedades en ContentPage y siete de Label, suelen aparecer como atributos XML.

Existen muchos métodos abreviados para establecer los valores de estas propiedades. Algunas propiedades son tipos de datos básicos: por ejemplo, las propiedades y Text son de tipo String, Rotation es de tipo Doubley (que es true de forma predeterminada y IsVisible se establece aquí solo para la ilustración) es de tipo Boolean.Title

La HorizontalTextAlignment propiedad es de tipo TextAlignment, que es una enumeración. Para una propiedad de cualquier tipo de enumeración, todo lo que necesita proporcionar es un nombre de miembro.

Sin embargo, para las propiedades de tipos más complejos, se usan convertidores para analizar el XAML. Estas son clases de Xamarin.Forms que derivan de TypeConverter. Muchas son clases públicas, pero algunas no. Para este archivo XAML determinado, varias de estas clases desempeñan un papel en segundo plano:

  • LayoutOptionsConverter para la VerticalOptions propiedad
  • FontSizeConverter para la FontSize propiedad
  • ColorTypeConverter para la TextColor propiedad

Estos convertidores rigen la sintaxis permitida de la configuración de la propiedad.

ThicknessTypeConverter puede controlar uno, dos o cuatro números separados por comas. Si se proporciona un número, se aplica a los cuatro lados. Con dos números, el primero es el relleno izquierdo y derecho, y el segundo es superior e inferior. Cuatro números están en el orden izquierdo, superior, derecho e inferior.

LayoutOptionsConverter puede convertir los nombres de los campos estáticos públicos de la LayoutOptions estructura en valores de tipo LayoutOptions.

FontSizeConverter puede controlar un NamedSize miembro o un tamaño de fuente numérico.

ColorTypeConverter acepta los nombres de los campos estáticos públicos de la Color estructura o los valores RGB hexadecimales, con o sin un canal alfa, precedido por un signo de número (#). Esta es la sintaxis sin un canal alfa:

TextColor="#rrggbb"

Cada una de las letras pequeñas es un dígito hexadecimal. Este es el modo en que se incluye un canal alfa:

TextColor="#aarrggbb">

Para el canal alfa, tenga en cuenta que FF es totalmente opaco y 00 es totalmente transparente.

Otros dos formatos permiten especificar solo un único dígito hexadecimal para cada canal:

TextColor="#rgb" TextColor="#argb"

En estos casos, el dígito se repite para formar el valor. Por ejemplo, #CF3 es el color RGB CC-FF-33.

Al ejecutar el programa XamlSamples , MainPage se muestra . Para ver el nuevo HelloXamlPage , puedes establecerlo como la nueva página de inicio en el archivo App.xaml.cs o navegar a la nueva página desde MainPage.

Para implementar la navegación, cambie primero el código en el constructor App.xaml.cs para que se cree un NavigationPage objeto:

public App()
{
    InitializeComponent();
    MainPage = new NavigationPage(new MainPage());
}

En el constructor MainPage.xaml.cs , puedes crear un sencillo Button y usar el controlador de eventos para navegar a HelloXamlPage:

public MainPage()
{
    InitializeComponent();

    Button button = new Button
    {
        Text = "Navigate!",
        HorizontalOptions = LayoutOptions.Center,
        VerticalOptions = LayoutOptions.Center
    };

    button.Clicked += async (sender, args) =>
    {
        await Navigation.PushAsync(new HelloXamlPage());
    };

    Content = button;
}

Establecer la Content propiedad de la página reemplaza el valor de la Content propiedad en el archivo XAML. Al compilar e implementar la nueva versión de este programa, aparece un botón en la pantalla. Al presionarlo, se desplaza a HelloXamlPage. Esta es la página resultante en iPhone, Android y UWP:

Texto de etiqueta girado

Puedes volver a MainPage usar el < botón Atrás en iOS, usando la flecha izquierda en la parte superior de la página o en la parte inferior del teléfono en Android, o usando la flecha izquierda en la parte superior de la página de Windows 10.

No dude en experimentar con xaml para diferentes formas de representar .Label Si necesita insertar caracteres Unicode en el texto, puede usar la sintaxis XML estándar. Por ejemplo, para colocar el saludo en comillas inteligentes, use:

<Label Text="&#x201C;Hello, XAML!&#x201D;" … />

Este es el aspecto siguiente:

Texto de etiqueta girado con caracteres Unicode

Interacciones de código y XAML

El ejemplo HelloXamlPage contiene solo un único Label en la página, pero esto es muy inusual. La mayoría ContentPage de los derivados establecen la Content propiedad en un diseño de algún tipo, como .StackLayout La Children propiedad de StackLayout se define como de tipo IList<View> , pero en realidad es un objeto de tipo ElementCollection<View>, y esa colección se puede rellenar con varias vistas u otros diseños. En XAML, estas relaciones de elementos primarios y secundarios se establecen con la jerarquía XML normal. Este es un archivo XAML para una nueva página denominada XamlPlusCodePage:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand" />
    </StackLayout>
</ContentPage>

Este archivo XAML está sintácticamente completo y este es el aspecto siguiente:

Varios controles de una página

Sin embargo, es probable que considere que este programa sea funcionalmente deficiente. Tal vez el Slider se supone que hace que muestre Label el valor actual y que Button probablemente esté pensado para hacer algo dentro del programa.

Como verá en la parte 4. Datos básicos de enlace de datos, el trabajo de mostrar un Slider valor mediante un Label se puede controlar completamente en XAML con un enlace de datos. Pero es útil ver primero la solución de código. Incluso así, controlar el Button clic definitivamente requiere código. Esto significa que el archivo de código subyacente para XamlPlusCodePage debe contener controladores para el ValueChanged evento de Slider y el Clicked evento de Button. Vamos a agregarlos:

namespace XamlSamples
{
    public partial class XamlPlusCodePage
    {
        public XamlPlusCodePage()
        {
            InitializeComponent();
        }

        void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        {

        }

        void OnButtonClicked(object sender, EventArgs args)
        {

        }
    }
}

Estos controladores de eventos no necesitan ser públicos.

De nuevo en el archivo XAML, las Slider etiquetas y Button deben incluir atributos para los ValueChanged eventos y Clicked que hacen referencia a estos controladores:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamlSamples.XamlPlusCodePage"
             Title="XAML + Code Page">
    <StackLayout>
        <Slider VerticalOptions="CenterAndExpand"
                ValueChanged="OnSliderValueChanged" />

        <Label Text="A simple Label"
               Font="Large"
               HorizontalOptions="Center"
               VerticalOptions="CenterAndExpand" />

        <Button Text="Click Me!"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Clicked="OnButtonClicked" />
    </StackLayout>
</ContentPage>

Observe que la asignación de un controlador a un evento tiene la misma sintaxis que asignar un valor a una propiedad.

Si el controlador del ValueChanged evento de Slider va a usar para Label mostrar el valor actual, el controlador debe hacer referencia a ese objeto desde el código. Label necesita un nombre, que se especifica con el x:Name atributo .

<Label x:Name="valueLabel"
       Text="A simple Label"
       Font="Large"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />

El x prefijo del x:Name atributo indica que este atributo es intrínseco a XAML.

El nombre que asigne al x:Name atributo tiene las mismas reglas que los nombres de variable de C#. Por ejemplo, debe comenzar con una letra o un carácter de subrayado y no contener espacios incrustados.

Ahora el ValueChanged controlador de eventos puede establecer para Label mostrar el nuevo Slider valor. El nuevo valor está disponible en los argumentos del evento:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = args.NewValue.ToString("F3");
}

O bien, el controlador podría obtener el Slider objeto que genera este evento a partir del sender argumento y obtener la Value propiedad de esa:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    valueLabel.Text = ((Slider)sender).Value.ToString("F3");
}

Cuando se ejecuta por primera vez el programa, Label no muestra el Slider valor porque el ValueChanged evento aún no se ha desencadenado. Pero cualquier manipulación de Slider hace que se muestre el valor:

Valor del control deslizante mostrado

Ahora para .Button Vamos a simular una respuesta a un Clicked evento mostrando una alerta con el Text del botón . El controlador de eventos puede convertir el sender argumento de forma segura en y Button , a continuación, acceder a sus propiedades:

async void OnButtonClicked(object sender, EventArgs args)
{
    Button button = (Button)sender;
    await DisplayAlert("Clicked!",
        "The button labeled '" + button.Text + "' has been clicked",
        "OK");
}

El método se define como async porque el DisplayAlert método es asincrónico y debe estar precedido del await operador , que devuelve cuando se completa el método. Dado que este método obtiene el Button desencadenamiento del evento del sender argumento , se podría usar el mismo controlador para varios botones.

Has visto que un objeto definido en XAML puede desencadenar un evento que se controla en el archivo de código subyacente y que el archivo de código subyacente puede tener acceso a un objeto definido en XAML con el nombre asignado con el x:Name atributo . Estas son las dos formas fundamentales de interactuar con el código y XAML.

Para obtener información adicional sobre cómo funciona XAML, examine el archivo XamlPlusCode.xaml.g.cs recién generado, que ahora incluye cualquier nombre asignado a cualquier x:Name atributo como campo privado. Esta es una versión simplificada de ese archivo:

public partial class XamlPlusCodePage : ContentPage {

    private Label valueLabel;

    private void InitializeComponent() {
        this.LoadFromXaml(typeof(XamlPlusCodePage));
        valueLabel = this.FindByName<Label>("valueLabel");
    }
}

La declaración de este campo permite que la variable se use libremente en cualquier parte del XamlPlusCodePage archivo de clase parcial bajo su jurisdicción. En tiempo de ejecución, el campo se asigna después de analizar el CÓDIGO XAML. Esto significa que el valueLabel campo es null cuando el XamlPlusCodePage constructor comienza pero es válido después InitializeComponent de llamar a .

Después InitializeComponent de devolver el control al constructor, los objetos visuales de la página se han construido como si se hubieran creado e inicializado en el código. El archivo XAML ya no desempeña ningún rol en la clase . Puede manipular estos objetos en la página de cualquier manera que desee, por ejemplo, agregando vistas a StackLayouto estableciendo la Content propiedad de la página en otra cosa completamente. Puede "recorrer el árbol" examinando la Content propiedad de la página y los elementos de las Children colecciones de diseños. Puede establecer propiedades en las vistas a las que se tiene acceso de esta manera o asignar controladores de eventos a ellas dinámicamente.

No dudes. Es tu página y XAML es solo una herramienta para crear su contenido.

Resumen

Con esta introducción, has visto cómo un archivo XAML y un archivo de código contribuyen a una definición de clase y cómo interactúan los archivos XAML y de código. Pero XAML también tiene sus propias características sintácticas únicas que permiten su uso de manera muy flexible. Puede empezar a explorarlos en la parte 2. Sintaxis XAML esencial.