Análisis detallado de inicio rápido de Xamarin.Forms

En Inicio rápido de Xamarin.Forms se ha creado la aplicación Notes. En este artículo se revisa lo que se ha compilado para comprender los aspectos fundamentales del funcionamiento de las aplicaciones de Xamarin.Forms Shell.

Introducción a Visual Studio

Visual Studio organiza el código en soluciones y proyectos. Una solución es un contenedor que puede incluir uno o varios proyectos. Un proyecto puede ser una aplicación, una biblioteca auxiliar o una aplicación de prueba, entre otros. La aplicación Notes consta de una solución que contiene tres proyectos, como se muestra en la captura de pantalla siguiente:

Explorador de soluciones de Visual Studio

Los proyectos son:

  • Notes: este proyecto es el de la biblioteca de .NET Standard que incluye todo el código compartido y la interfaz de usuario compartida.
  • Notes.Android: este proyecto incluye el código específico de Android y es el punto de entrada de la aplicación Android.
  • Notes.iOS: este proyecto incluye el código específico de iOS y es el punto de entrada de la aplicación iOS.

Anatomía de una aplicación de Xamarin.Forms

En la captura de pantalla siguiente se muestra el contenido del proyecto de biblioteca de .NET Standard Notes en Visual Studio:

Contenido del proyecto de .NET Standard de Phoneword

El proyecto tiene un nodo Dependencias que contiene los nodos NuGet y SDK:

  • NuGet: paquetes NuGet Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json y sqlite-net-pcl que se han agregado al proyecto.
  • SDK: el metapaquete NETStandard.Library que hace referencia al conjunto completo de paquetes NuGet que definen .NET Standard.

Introducción a Visual Studio para Mac

Visual Studio para Mac sigue la práctica de Visual Studio consistente en organizar el código en soluciones y proyectos. Una solución es un contenedor que puede incluir uno o varios proyectos. Un proyecto puede ser una aplicación, una biblioteca auxiliar o una aplicación de prueba, entre otros. La aplicación Notes consta de una solución que contiene tres proyectos, como se muestra en la captura de pantalla siguiente:

Panel de solución de Visual Studio para Mac

Los proyectos son:

  • Notes: este proyecto es el de la biblioteca de .NET Standard que incluye todo el código compartido y la interfaz de usuario compartida.
  • Notes.Android: este proyecto incluye el código específico de Android y es el punto de entrada de las aplicaciones Android.
  • Notes.iOS: este proyecto incluye el código específico de iOS y es el punto de entrada de las aplicaciones iOS.

Anatomía de una aplicación de Xamarin.Forms

En la captura de pantalla siguiente se muestra el contenido del proyecto de biblioteca de .NET Standard Notes en Visual Studio para Mac:

Contenido del proyecto de biblioteca de .NET Standard Phoneword

El proyecto tiene un nodo Dependencias que contiene los nodos NuGet y SDK:

  • NuGet: paquetes NuGet Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json y sqlite-net-pcl que se han agregado al proyecto.
  • SDK: el metapaquete NETStandard.Library que hace referencia al conjunto completo de paquetes NuGet que definen .NET Standard.

El proyecto también consta de varios archivos:

  • Data\NoteDatabase.cs: esta clase contiene código para crear la base de datos, leer datos de ella, escribir datos en ella y eliminarlos.
  • Models\Note.cs: esta clase define un modelo Note cuyas instancias almacenarán datos sobre cada nota en la aplicación.
  • Views\AboutPage.xaml: el marcado XAML para la clase AboutPage, que define la interfaz de usuario para la página de información.
  • Views\AboutPage.xaml.cs: el código subyacente para la clase AboutPage, que contiene la lógica de negocios que se ejecuta cuando el usuario interactúa con la página.
  • Views\NotesPage.xaml: el marcado XAML para la clase NotesPage, que define la interfaz de usuario para la página que se muestra al iniciar la aplicación.
  • Views\NotesPage.xaml.cs: el código subyacente para la clase NotesPage, que contiene la lógica de negocios que se ejecuta cuando el usuario interactúa con la página.
  • Views\NoteEntryPage.xaml: el marcado XAML para la clase NoteEntryPage, que define la interfaz de usuario para la página que se muestra cuando el usuario escribe una nota.
  • Views\NoteEntryPage.xaml.cs: el código subyacente para la clase NoteEntryPage, que contiene la lógica de negocios que se ejecuta cuando el usuario interactúa con la página.
  • App.xaml: el marcado XAML para la clase App, que define un diccionario de recursos para la aplicación.
  • App.xaml.cs: el código subyacente para la clase App, que es el responsable de crear instancias de la aplicación de Shell y para controlar los eventos del ciclo de vida de la aplicación.
  • AppShell.xaml: el marcado XAML para la clase AppShell, que define la jerarquía visual de la aplicación.
  • AppShell.xaml.cs: el código subyacente para la clase AppShell, que crea una ruta para NoteEntryPage, a fin de que se pueda acceder mediante programación.
  • AssemblyInfo.cs: este archivo contiene un atributo de aplicación sobre el proyecto, que se aplica en el nivel de ensamblado.

Para obtener más información sobre la anatomía de una aplicación de Xamarin.iOS, consulte Anatomía de una aplicación de Xamarin.iOS. Para obtener más información sobre la anatomía de una aplicación de Xamarin.Android, consulte Anatomía de una aplicación de Xamarin.Android.

Arquitectura y aspectos básicos de la aplicación

Una aplicación de Xamarin.Forms tiene la misma arquitectura que una aplicación multiplataforma tradicional. El código compartido normalmente se coloca en una biblioteca de .NET Standard, y las aplicaciones específicas de la plataforma consumen el código compartido. En el diagrama siguiente se muestra información general de esta relación para la aplicación Notes:

Arquitectura de Notes

Para maximizar la reutilización del código de inicio, las aplicaciones de Xamarin.Forms tienen una clase única denominada App, que es responsable de crear instancias de la aplicación en cada plataforma, como se muestra en el ejemplo de código siguiente:

using Xamarin.Forms;

namespace Notes
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
            MainPage = new AppShell();
        }
        // ...
    }
}

Este código establece la propiedad MainPage de la clase App en el objeto AppShell. La clase AppShell define la jerarquía visual de la aplicación. Shell toma esta jerarquía visual y genera la interfaz de usuario para ella. Para más información sobre cómo definir la jerarquía visual de la aplicación, consulte Jerarquía visual de la aplicación.

Además, el archivo AssemblyInfo.cs contiene un único atributo de aplicación, que se aplica en el nivel de ensamblado:

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

El atributo XamlCompilation activa el compilador XAML, para que XAML se compile directamente en lenguaje intermedio. Para obtener más información, consulte Compilación XAML.

Inicio de la aplicación en cada plataforma

La forma en que se inicia la aplicación en cada plataforma es específica de la plataforma.

iOS

Para abrir la página inicial de Xamarin.Forms en iOS, en el proyecto Notes.iOS se define la clase AppDelegate, que hereda de la clase FormsApplicationDelegate:

namespace Notes.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            return base.FinishedLaunching(app, options);
        }
    }
}

El reemplazo FinishedLaunching inicializa el marco de Xamarin.Forms mediante una llamada al método Init. Esto hace que la implementación específica de iOS de Xamarin.Forms se cargue en la aplicación antes de que se establezca el controlador de vista raíz mediante la llamada al método LoadApplication.

Android

Para iniciar la página de inicio de Xamarin.Forms en Android, el proyecto Notes.Android incluye código para crear un elemento Activity con el atributo MainLauncher, y la actividad se hereda de la clase FormsAppCompatActivity:

namespace Notes.Droid
{
    [Activity(Label = "Notes",
              Icon = "@mipmap/icon",
              Theme = "@style/MainTheme",
              MainLauncher = true,
              ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
    }
}

El reemplazo OnCreate inicializa el marco de Xamarin.Forms mediante una llamada al método Init. Esto provoca que la implementación específica de Android de Xamarin.Forms se cargue en la aplicación antes de que lo haga la aplicación de Xamarin.Forms.

Jerarquía visual de la aplicación

Las aplicaciones de Xamarin.Forms Shell definen la jerarquía visual de la aplicación en una clase que genera subclases de la clase Shell. En la aplicación de notas, se trata de la clase Appshell:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Notes.Views"
       x:Class="Notes.AppShell">
    <TabBar>
        <ShellContent Title="Notes"
                      Icon="icon_feed.png"
                      ContentTemplate="{DataTemplate views:NotesPage}" />
        <ShellContent Title="About"
                      Icon="icon_about.png"
                      ContentTemplate="{DataTemplate views:AboutPage}" />
    </TabBar>
</Shell>

Este XAML consta de dos objetos principales:

  • TabBar. El TabBar representa la barra de pestañas de la parte inferior y debe usarse cuando el patrón de navegación de la aplicación usa pestañas en la parte inferior. El objeto TabBar es un elemento secundario del objeto Shell.
  • ShellContent, que representa los objetos ContentPage para cada pestaña de TabBar. Cada objeto ShellContent es un elemento secundario del objeto TabBar.

Estos objetos no representan ninguna interfaz de usuario, sino más bien la organización de la jerarquía visual de la aplicación. Shell tomará estos elementos y generará la interfaz de usuario de navegación del contenido. Por lo tanto, la clase AppShell define dos páginas que se pueden navegar desde las pestañas inferiores. Las páginas se crean a petición, en respuesta a la navegación.

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

Interfaz de usuario

Existen varios grupos de controles que se usan para crear la interfaz de usuario de una aplicación de Xamarin.Forms:

  1. Páginas: las páginas de Xamarin.Forms representan pantallas de aplicaciones móviles multiplataforma. En la aplicación Notes se usa la clase ContentPage para mostrar pantallas únicas. Para obtener más información sobre las páginas de códigos, vea Páginas de Xamarin.Forms.
  2. Vistas: las vistas de Xamarin.Forms son los controles que se muestran en la interfaz de usuario, como etiquetas, botones y cuadros de entrada de texto. En la aplicación Notes terminada se usan las vistas CollectionView, Editor y Button. Para obtener más información sobre las vistas, consulte Vistas de Xamarin.Forms.
  3. Diseños: los diseños de Xamarin.Forms son contenedores que se usan para crear vistas en estructuras lógicas. En la aplicación Notes se usa la clase StackLayout para organizar las vistas en una pila vertical y la clase Grid para organizar los botones de forma horizontal. Para obtener más información sobre los diseños, consulte Diseños de Xamarin.Forms.

En tiempo de ejecución, cada control se asignará a su equivalente nativo, que es lo que se representará.

Diseño

En la aplicación Notes se usa StackLayout para simplificar el desarrollo de aplicaciones multiplataforma mediante la disposición automática de las vistas en la pantalla, independientemente del tamaño de esta. Cada elemento secundario se coloca uno detrás del otro, ya sea horizontal o verticalmente, en el orden en el que se ha agregado. La cantidad de espacio que usará la clase StackLayout depende de cómo se establezcan las propiedades HorizontalOptions y VerticalOptions, pero StackLayout intentará usar toda la pantalla de forma predeterminada.

En el código XAML siguiente se muestra un ejemplo de uso de una clase StackLayout para organizar el control NoteEntryPage:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    ...    
    <StackLayout Margin="{StaticResource PageMargin}">
        <Editor Placeholder="Enter your note"
                Text="{Binding Text}"
                HeightRequest="100" />
        <Grid>
            ...
        </Grid>
    </StackLayout>    
</ContentPage>

De forma predeterminada, StackLayout asume una orientación vertical. Pero se puede cambiar a una orientación horizontal si se establece la propiedad StackLayout.Orientation en el miembro de enumeración StackOrientation.Horizontal.

Nota:

El tamaño de las vistas se puede establecer a través de las propiedades HeightRequest y WidthRequest.

Para más información sobre la clase StackLayout, consulte Xamarin.Forms StackLayout.

Responder a la interacción del usuario

Un objeto que se ha definido en XAML puede desencadenar un evento que se controla en el archivo de código subyacente. En el ejemplo de código siguiente se muestra el método OnSaveButtonClicked del código subyacente de la clase NoteEntryPage, que se ejecuta en respuesta al evento Clicked que se desencadena en el botón Guardar.

async void OnSaveButtonClicked(object sender, EventArgs e)
{
    var note = (Note)BindingContext;
    note.Date = DateTime.UtcNow;
    if (!string.IsNullOrWhiteSpace(note.Text))
    {
        await App.Database.SaveNoteAsync(note);
    }
    await Shell.Current.GoToAsync("..");
}

El método OnSaveButtonClicked guarda la nota en la base de datos y regresa a la página anterior. Para más información sobre la navegación, consulte Navegación.

Nota:

El archivo de código subyacente de una clase XAML puede tener acceso a un objeto que se ha definido en XAML con el nombre asignado a él con el atributo x:Name. El valor que se ha asignado a este atributo tiene las mismas reglas que las variables de C#, ya que debe comenzar con una letra o guion bajo y no contener espacios incrustados.

La conexión del botón Guardar con el método OnSaveButtonClicked se realiza en el marcado XAML de la clase NoteEntryPage:

<Button Text="Save"
        Clicked="OnSaveButtonClicked" />

Listas

CollectionView es responsable de mostrar una colección de elementos en una lista. De manera predeterminada, los elementos de la lista se muestran verticalmente y cada elemento se muestra en una sola fila.

En el ejemplo de código siguiente se muestra el elemento CollectionView de NotesPage:

<CollectionView x:Name="collectionView"
                Margin="{StaticResource PageMargin}"
                SelectionMode="Single"
                SelectionChanged="OnSelectionChanged">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical"
                           ItemSpacing="10" />
    </CollectionView.ItemsLayout>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                <Label Text="{Binding Text}"
                       FontSize="Medium" />
                <Label Text="{Binding Date}"
                       TextColor="{StaticResource TertiaryColor}"
                       FontSize="Small" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

El diseño de cada fila de CollectionView se define dentro del elemento CollectionView.ItemTemplate y se usa el enlace de datos para mostrar las notas recuperadas por la aplicación. La propiedad CollectionView.ItemsSource está establecida en el origen de datos, en NotesPage.xaml.cs:

protected override async void OnAppearing()
{
    base.OnAppearing();

    collectionView.ItemsSource = await App.Database.GetNotesAsync();
}

Este código rellena CollectionView con todas las notas almacenadas en la base de datos y se ejecuta cuando aparece la página.

Cuando se selecciona un elemento en CollectionView, se desencadena el evento SelectionChanged. Cuando se desencadena el evento, se ejecuta un controlador de eventos denominado OnSelectionChanged:

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // ...
    }
}

El evento SelectionChanged puede acceder al objeto asociado al elemento a través de la propiedad e.CurrentSelection.

Para obtener más información sobre la clase CollectionView, consulte CollectionView de Xamarin.Forms.

La navegación se realiza en una aplicación de Shell mediante la especificación de un URI al que navegar. Los URI de navegación tienen tres componentes:

  • Una ruta, que define la ruta de acceso al contenido que existe como parte de la jerarquía visual de Shell.
  • Una página. Las páginas que no existen en la jerarquía visual de Shell se pueden insertar en la pila de navegación desde cualquier lugar dentro de una aplicación de Shell. Por ejemplo, NoteEntryPage no se define en la jerarquía visual de Shell, pero se puede insertar en la pila de navegación si es necesario.
  • Uno o varios parámetros de consulta. Los parámetros de consulta son parámetros que se pueden pasar a la página de destino durante la navegación.

No es necesario que un URI de navegación incluya los tres componentes pero, cuando lo hace, la estructura es: //route/page?queryParameters

Nota:

Las rutas se pueden definir en los elementos de la jerarquía visual de Shell a través de la propiedad Route. Sin embargo, si la propiedad Route no está establecida, como en la aplicación de notas, se genera una ruta en tiempo de ejecución.

Para más información sobre la navegación de Shell, consulte Navegación de Xamarin.Forms Shell.

Registro de rutas

Para ir a una página que no existe en la jerarquía visual de Shell, es necesario que se registre primero con el sistema de enrutamiento de Shell. con el método Routing.RegisterRoute. En la aplicación de notas, esto ocurre en el constructor AppShell:

public partial class AppShell : Shell
{
    public AppShell()
    {
        // ...
        Routing.RegisterRoute(nameof(NoteEntryPage), typeof(NoteEntryPage));
    }
}

En este ejemplo, se registra una ruta denominada NoteEntryPage con respecto al tipo NoteEntryPage. Luego, es posible navegar a esta página desde cualquier lugar de la aplicación mediante la navegación basada en el URI.

Realización de la navegación

La navegación se realiza mediante el método GoToAsync, que acepta un argumento que representa la ruta a la que navegar:

await Shell.Current.GoToAsync("NoteEntryPage");

En este ejemplo, se navega a NoteEntryPage.

Importante

Se crea una pila de navegación cuando se navega a una página que no está en la jerarquía visual de Shell.

Al navegar a una página, los datos se pueden pasar a la página como un parámetro de consulta:

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // Navigate to the NoteEntryPage, passing the ID as a query parameter.
        Note note = (Note)e.CurrentSelection.FirstOrDefault();
        await Shell.Current.GoToAsync($"{nameof(NoteEntryPage)}?{nameof(NoteEntryPage.ItemId)}={note.ID.ToString()}");
    }
}

En este ejemplo, se recupera el elemento actualmente seleccionado en CollectionView y navega a NoteEntryPage, con el valor de propiedad ID del objeto Note que se pasa como parámetro de consulta a la propiedad NoteEntryPage.ItemId.

Para recibir los datos pasados, la clase NoteEntryPage se decora con el atributo QueryPropertyAttribute.

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }
    }
    // ...
}

El primer argumento de QueryPropertyAttribute especifica el nombre de la propiedad ItemId que recibirá los datos, mientras que el segundo argumento especifica el identificador del parámetro de consulta. Por tanto, el elemento QueryPropertyAttribute del ejemplo anterior especifica que la propiedad ItemId recibirá los datos pasados al parámetro de consulta ItemId del URI en la llamada al método GoToAsync. Luego, la propiedad ItemId llama al método LoadNote para recuperar la nota del dispositivo.

La navegación hacia atrás se puede llevar a cabo si especifica ".." como el argumento para el método GoToAsync:

await Shell.Current.GoToAsync("..");

Para más información sobe la navegación hacia atrás, consulte Navegación hacia atrás.

Enlace de datos

El enlace de datos se usa para simplificar la forma en que una aplicación de Xamarin.Forms muestra sus datos e interactúa con ellos. Establece una conexión entre la interfaz de usuario y la aplicación subyacente. La clase BindableObject contiene gran parte de la infraestructura para admitir el enlace de datos.

El enlace de datos conecta dos objetos, denominados origen y destino. El objeto de origen proporciona los datos. El objeto de destino usa (y, a menudo, muestra) los datos del objeto de origen. Por ejemplo, un control Editor (objeto de destino) normalmente enlazará su propiedad Text a una propiedad string pública en un objeto de origen. En el diagrama siguiente se muestra la relación de enlace:

Enlace de datos

El principal beneficio del enlace de datos es que ya no tiene que preocuparse de sincronizar los datos entre las vistas y el origen de datos. Los cambios en el objeto de origen se insertan automáticamente en el objeto de destino en segundo plano por medio del marco de enlace, mientras que los cambios en el objeto de destino pueden insertarse de manera opcional en el objeto de origen.

El establecimiento del enlace de datos es un proceso de dos pasos:

  • La propiedad BindingContext del objeto de destino se debe establecer en el de origen.
  • Es necesario establecer un enlace entre el destino y el origen. En XAML, esto se consigue mediante la extensión de marcado Binding.

En la aplicación Notes, el destino de enlace es el elemento Editor que muestra una nota, mientras que la instancia de Note establecida como BindingContext de NoteEntryPage es el origen de enlace. Inicialmente, BindingContext de NoteEntryPage se establece cuando se ejecuta el constructor de página:

public NoteEntryPage()
{
    // ...
    BindingContext = new Note();
}

En este ejemplo, el BindingContext de la página está establecido en una Note nueva cuando se crea NoteEntryPage. Esto controla el escenario en que se agrega una nota nueva a la aplicación.

Además, el BindingContext de la página también se establece cuando se produce la navegación a NoteEntryPage, siempre que haya una nota existente seleccionada en NotesPage:

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }

        async void LoadNote(string itemId)
        {
            try
            {
                int id = Convert.ToInt32(itemId);
                // Retrieve the note and set it as the BindingContext of the page.
                Note note = await App.Database.GetNoteAsync(id);
                BindingContext = note;
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to load note.");
            }
        }    
        // ...    
    }
}

En este ejemplo, cuando se produce la navegación por la página, el BindingContextse establece en el objeto Note seleccionado una vez que se recupera de la base de datos.

Importante

Aunque la propiedad BindingContext de cada objeto de destino se puede establecer de manera individual, no es necesario hacerlo. BindingContext es una propiedad especial que heredan todos sus elementos secundarios. Por tanto, cuando la propiedad BindingContext de ContentPage se establece en una instancia de Note, todos los elementos secundarios de ContentPage tienen la misma propiedad BindingContext y se pueden enlazar a propiedades públicas del objeto Note.

Después, el objeto Editor de NoteEntryPage se enlaza a la propiedad Text del objeto Note:

<Editor Placeholder="Enter your note"
        Text="{Binding Text}" />

Se establece un enlace entre la propiedad Editor.Text y la propiedad Text del objeto de origen. Los cambios realizados en Editor se propagarán de forma automática al objeto Note. De forma similar, si se realizan cambios en la propiedad Note.Text, el motor de enlace de Xamarin.Forms también actualizará el contenido de Editor. Esto se conoce como enlace bidireccional.

Para obtener más información sobre el enlace de datos, consulte Enlace de datos de Xamarin.Forms.

Aplicación de estilos

Las aplicaciones de Xamarin.Forms suelen contener varios elementos visuales que tienen un aspecto idéntico. Establecer la apariencia de cada elemento visual puede ser repetitivo y propenso a errores. En su lugar, se pueden crear estilos que definan el aspecto y, después, aplicarlos a los elementos visuales necesarios.

La clase Style agrupa una colección de valores de propiedad en un objeto que después se puede aplicar a varias instancias de elementos visuales. Los estilos se almacenan en un objeto ResourceDictionary, ya sea en el nivel de la aplicación, de la página o de la vista. La elección de dónde se puede definir un elemento Style afecta a dónde se puede usar:

  • Las instancias de Style definidas en el nivel de aplicación se pueden aplicar en toda la aplicación.
  • Las instancias de Style definidas en el nivel de página se pueden aplicar a la página y a sus elementos secundarios.
  • Las instancias de Style definidas en el nivel de vista se pueden aplicar a la vista y a sus elementos secundarios.

Importante

Todos los estilos que se usen en la aplicación se almacenan en el diccionario de recursos de la aplicación para evitar la duplicación. Pero el código de XAML que es específico de una página no debería incluirse en el diccionario de recursos de la aplicación, dado que los recursos se analizarán en el inicio de la aplicación en lugar de cuando los solicite una página. Para más información, consulte Reducción del tamaño del diccionario de recursos de aplicación.

Cada instancia de Style contiene una colección de uno o varios objetos Setter, donde cada objeto Setter tiene un elemento Property y un elemento Value. Property es el nombre de la propiedad enlazable del elemento al que se aplica el estilo y Value es el valor que se aplica a la propiedad. En el ejemplo de código siguiente se muestra un estilo de NoteEntryPage:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    <ContentPage.Resources>
        <!-- Implicit styles -->
        <Style TargetType="{x:Type Editor}">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>
        ...
    </ContentPage.Resources>
    ...
</ContentPage>

Este estilo se aplica a cualquier instancia de Editor de la página.

Al crear un elemento Style, siempre se requiere la propiedad TargetType.

Nota:

Normalmente, la aplicación de estilo a una aplicación Xamarin.Forms se realiza mediante estilos XAML. Aun así, Xamarin.Forms también admite aplicar estilo a los elementos visuales mediante hojas de estilo CSS (CSS). Para obtener más información, vea Aplicación de estilos para aplicaciones Xamarin.Forms con hojas de estilo (CSS).

Para obtener más información sobre los estilos XAML, vea Aplicación de estilo a aplicaciones Xamarin.Forms con estilos XAML.

Prueba e implementación

Tanto Visual Studio para Mac como Visual Studio ofrecen numerosas opciones para probar e implementar una aplicación. Depurar aplicaciones es una parte común del ciclo de vida del desarrollo de la aplicación y ayuda a diagnosticar problemas de código. Para obtener más información, consulte Set a Breakpoint (Establecer un punto de interrupción), Step Through Code (Recorrer el código paso a paso) y Output Information to the Log Window (Información de salida para la ventana Registro).

Los simuladores son un buen lugar para comenzar a implementar y probar una aplicación, y cuentan con una funcionalidad que resulta útil a la hora de probar las aplicaciones. Sin embargo, los usuarios no usarán la aplicación final en un simulador, por lo que las aplicaciones deben probarse en dispositivos reales desde el primer momento y con frecuencia. Para obtener más información sobre el aprovisionamiento de dispositivos de iOS, consulte Aprovisionamiento de dispositivos. Para obtener más información sobre el aprovisionamiento de dispositivos de Android, consulte Configurar el dispositivo para el desarrollo.

Pasos siguientes

En este análisis detallado se han examinado los aspectos fundamentales del desarrollo de aplicaciones con Xamarin.Forms Shell. Se recomienda que, como paso siguiente, lea sobre las funcionalidades que se indican a continuación:

  • Xamarin.Forms Shell reduce la complejidad del desarrollo de aplicaciones móviles al proporcionar las características fundamentales que requieren la mayoría de las aplicaciones móviles. Para obtener más información, consulte Xamarin.Forms Shell.
  • Existen varios grupos de controles que se usan para crear la interfaz de usuario de una aplicación de Xamarin.Forms. Para obtener más información, vea Referencia de controles.
  • El enlace de datos es la técnica que consiste en vincular las propiedades de dos objetos para que los cambios en una propiedad se reflejen automáticamente en la otra propiedad. Para obtener más información, vea Enlace de datos.
  • Xamarin.Forms ofrece varias experiencias de navegación por páginas, en función del tipo de página que se use. Para obtener más información, consulte Navigation (Navegación).
  • Los estilos permiten reducir el uso de marcado repetitivo y conseguir que la apariencia de las aplicaciones pueda cambiarse con mayor facilidad. Para obtener más información, consulte Aplicación de estilos a aplicaciones Xamarin.Forms.
  • Las plantillas de datos permiten definir la presentación de los datos en las vistas admitidas. Para obtener más información, consulte Data Templates (Plantillas de datos).
  • Los efectos también permiten personalizar los controles nativos de cada plataforma. Los efectos se crean en proyectos específicos de la plataforma mediante la creación de subclases de la clase PlatformEffect. Para usarlos, se adjuntan a un control adecuado de Xamarin.Forms. Para obtener más información, consulte Effects (Efectos).
  • Cada página, diseño y control se representan de forma diferente en cada plataforma mediante una clase Renderer que, a su vez, crea un control nativo, lo organiza en la pantalla y agrega el comportamiento especificado al código compartido. Los desarrolladores pueden implementar sus propias clases Renderer personalizadas para personalizar la apariencia o el comportamiento de un control. Para obtener más información, consulte Custom Renderers (Representadores personalizados).
  • El código compartido puede tener acceso a la funcionalidad nativa mediante la clase DependencyService. Para obtener más información, consulte Accessing Native Features with DependencyService (Acceso a características nativas con DependencyService).

Encuentre más vídeos de Xamarin en Channel 9 y YouTube.