Análisis detallado de inicio rápido de Xamarin.FormsXamarin.Forms Quickstart Deep Dive

En Inicio rápido de Xamarin.Forms se ha creado la aplicación Notes.In the Xamarin.Forms Quickstart, the Notes application was built. 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.This article reviews what has been built to gain an understanding of the fundamentals of how Xamarin.Forms Shell applications work.

Introducción a Visual StudioIntroduction to Visual Studio

Visual Studio organiza el código en soluciones y proyectos.Visual Studio organizes code into Solutions and Projects. Una solución es un contenedor que puede incluir uno o varios proyectos.A solution is a container that can hold one or more projects. Un proyecto puede ser una aplicación, una biblioteca auxiliar o una aplicación de prueba, entre otros.A project can be an application, a supporting library, a test application, and more. La aplicación Notes consta de una solución que contiene tres proyectos, como se muestra en la captura de pantalla siguiente:The Notes application consists of one solution containing three projects, as shown in the following screenshot:

Explorador de soluciones de Visual Studio

Los proyectos son:The projects are:

  • 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 – This project is the .NET Standard library project that holds all of the shared code and shared UI.
  • Notes.Android: este proyecto incluye el código específico de Android y es el punto de entrada de la aplicación Android.Notes.Android – This project holds Android-specific code and is the entry point for the Android application.
  • Notes.iOS: este proyecto incluye el código específico de iOS y es el punto de entrada de la aplicación iOS.Notes.iOS – This project holds iOS-specific code and is the entry point for the iOS application.

Anatomía de una aplicación de Xamarin.FormsAnatomy of a Xamarin.Forms application

En la captura de pantalla siguiente se muestra el contenido del proyecto de biblioteca de .NET Standard Notes en Visual Studio:The following screenshot shows the contents of the Notes .NET Standard library project in Visual Studio:

Contenido del proyecto Phoneword de .NET Standard

El proyecto tiene un nodo Dependencias que contiene los nodos NuGet y SDK:The project has a Dependencies node that contains NuGet and SDK nodes:

  • NuGet: paquetes NuGet Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json y sqlite-net-pcl que se han agregado al proyecto.NuGet – the Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json, and sqlite-net-pcl NuGet packages that have been added to the project.
  • SDK: el metapaquete NETStandard.Library que hace referencia al conjunto completo de paquetes NuGet que definen .NET Standard.SDK – the NETStandard.Library metapackage that references the complete set of NuGet packages that define .NET Standard.

Introducción a Visual Studio para MacIntroduction to Visual Studio for Mac

Visual Studio para Mac sigue la práctica de Visual Studio consistente en organizar el código en soluciones y proyectos.Visual Studio for Mac follows the Visual Studio practice of organizing code into Solutions and Projects. Una solución es un contenedor que puede incluir uno o varios proyectos.A solution is a container that can hold one or more projects. Un proyecto puede ser una aplicación, una biblioteca auxiliar o una aplicación de prueba, entre otros.A project can be an application, a supporting library, a test application, and more. La aplicación Notes consta de una solución que contiene tres proyectos, como se muestra en la captura de pantalla siguiente:The Notes application consists of one solution containing three projects, as shown in the following screenshot:

Panel Solución de Visual Studio para Mac

Los proyectos son:The projects are:

  • 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 – This project is the .NET Standard library project that holds all of the shared code and shared UI.
  • Notes.Android: este proyecto incluye el código específico de Android y es el punto de entrada de las aplicaciones Android.Notes.Android – This project holds Android-specific code and is the entry point for Android applications.
  • Notes.iOS: este proyecto incluye el código específico de iOS y es el punto de entrada de las aplicaciones iOS.Notes.iOS – This project holds iOS specific-code and is the entry point for iOS applications.

Anatomía de una aplicación de Xamarin.FormsAnatomy of a Xamarin.Forms application

En la captura de pantalla siguiente se muestra el contenido del proyecto de biblioteca de .NET Standard Notes en Visual Studio para Mac:The following screenshot shows the contents of the Notes .NET Standard library project in Visual Studio for Mac:

Contenido del proyecto de biblioteca de .NET Standard Phoneword

El proyecto tiene un nodo Dependencias que contiene los nodos NuGet y SDK:The project has a Dependencies node that contains NuGet and SDK nodes:

  • NuGet: paquetes NuGet Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json y sqlite-net-pcl que se han agregado al proyecto.NuGet – the Xamarin.Forms, Xamarin.Essentials, Newtonsoft.Json, and sqlite-net-pcl NuGet packages that have been added to the project.
  • SDK: el metapaquete NETStandard.Library que hace referencia al conjunto completo de paquetes NuGet que definen .NET Standard.SDK – the NETStandard.Library metapackage that references the complete set of NuGet packages that define .NET Standard.

El proyecto también consta de varios archivos:The project also consists of multiple files:

  • Data\NoteDatabase.cs: esta clase contiene código para crear la base de datos, leer datos de ella, escribir datos en ella y eliminarlos.Data\NoteDatabase.cs – This class contains code to create the database, read data from it, write data to it, and delete data from it.
  • Models\Note.cs: esta clase define un modelo Note cuyas instancias almacenarán datos sobre cada nota en la aplicación.Models\Note.cs – This class defines a Note model whose instances store data about each note in the application.
  • 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 – The XAML markup for the AboutPage class, which defines the UI for the about page.
  • 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\AboutPage.xaml.cs – The code-behind for the AboutPage class, which contains the business logic that is executed when the user interacts with the page.
  • 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 – The XAML markup for the NotesPage class, which defines the UI for the page shown when the application launches.
  • 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\NotesPage.xaml.cs – The code-behind for the NotesPage class, which contains the business logic that is executed when the user interacts with the page.
  • 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 – The XAML markup for the NoteEntryPage class, which defines the UI for the page shown when the user enters a note.
  • 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.Views\NoteEntryPage.xaml.cs – The code-behind for the NoteEntryPage class, which contains the business logic that is executed when the user interacts with the page.
  • App.xaml: el marcado XAML para la clase App, que define un diccionario de recursos para la aplicación.App.xaml – The XAML markup for the App class, which defines a resource dictionary for the application.
  • 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.App.xaml.cs – The code-behind for the App class, which is responsible for instantiating the Shell application, and for handling application lifecycle events.
  • AppShell.xaml: el marcado XAML para la clase AppShell, que define la jerarquía visual de la aplicación.AppShell.xaml – The XAML markup for the AppShell class, which defines the visual hierarchy of the application.
  • 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.AppShell.xaml.cs – The code-behind for the AppShell class, which creates a route for the NoteEntryPage so that it can be navigated to programmatically.
  • AssemblyInfo.cs: este archivo contiene un atributo de aplicación sobre el proyecto, que se aplica en el nivel de ensamblado.AssemblyInfo.cs – This file contains an application attribute about the project, that is applied at the assembly level.

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.For more information about the anatomy of a Xamarin.iOS application, see Anatomy of a Xamarin.iOS Application. 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.For more information about the anatomy of a Xamarin.Android application, see Anatomy of a Xamarin.Android Application.

Arquitectura y aspectos básicos de la aplicaciónArchitecture and application fundamentals

Una aplicación de Xamarin.Forms tiene la misma arquitectura que una aplicación multiplataforma tradicional.A Xamarin.Forms application is architected in the same way as a traditional cross-platform application. 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.Shared code is typically placed in a .NET Standard library, and platform-specific applications consume the shared code. En el diagrama siguiente se muestra información general de esta relación para la aplicación Notes:The following diagram shows an overview of this relationship for the Notes application:

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:To maximize the reuse of startup code, Xamarin.Forms applications have a single class named App that is responsible for instantiating the application on each platform, as shown in the following code example:

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.This code sets the MainPage property of the App class to the AppShell object. La clase AppShell define la jerarquía visual de la aplicación.The AppShell class defines the visual hierarchy of the application. Shell toma esta jerarquía visual y genera la interfaz de usuario para ella.Shell takes this visual hierarchy and produces the user interface for it. 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.For more information about defining the visual hierarchy of the application, see Application visual hierarchy.

Además, el archivo AssemblyInfo.cs contiene un único atributo de aplicación, que se aplica en el nivel de ensamblado:In addition, the AssemblyInfo.cs file contains a single application attribute, that is applied at the assembly level:

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

El atributo XamlCompilation activa el compilador XAML, para que XAML se compile directamente en lenguaje intermedio.The XamlCompilation attribute turns on the XAML compiler, so that XAML is compiled directly into intermediate language. Para obtener más información, consulte Compilación XAML.For more information, see XAML Compilation.

Inicio de la aplicación en cada plataformaLaunch the application on each platform

La forma en que se inicia la aplicación en cada plataforma es específica de la plataforma.How the application is launched on each platform is specific to the platform.

iOSiOS

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:To launch the initial Xamarin.Forms page in iOS, the Notes.iOS project defines the AppDelegate class that inherits from the FormsApplicationDelegate class:

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.The FinishedLaunching override initializes the Xamarin.Forms framework by calling the Init method. 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.This causes the iOS-specific implementation of Xamarin.Forms to be loaded in the application before the root view controller is set by the call to the LoadApplication method.

AndroidAndroid

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:To launch the initial Xamarin.Forms page in Android, the Notes.Android project includes code that creates an Activity with the MainLauncher attribute, with the activity inheriting from the FormsAppCompatActivity class:

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.The OnCreate override initializes the Xamarin.Forms framework by calling the Init method. 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.This causes the Android-specific implementation of Xamarin.Forms to be loaded in the application before the Xamarin.Forms application is loaded.

Jerarquía visual de la aplicaciónApplication visual hierarchy

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.Xamarin.Forms Shell applications define the visual hierarchy of the application in a class that subclasses the Shell class. En la aplicación de notas, se trata de la clase Appshell:In the Notes application this is the Appshell class:

<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:This XAML consists of two main objects:

  • TabBar.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.The TabBar represents the bottom tab bar, and should be used when the navigation pattern for the application uses bottom tabs. El objeto TabBar es un elemento secundario del objeto Shell.The TabBar object is a child of the Shell object.
  • ShellContent, que representa los objetos ContentPage para cada pestaña de TabBar.ShellContent, which represents the ContentPage objects for each tab in the TabBar. Cada objeto ShellContent es un elemento secundario del objeto TabBar.Each ShellContent object is a child of the TabBar object.

Estos objetos no representan ninguna interfaz de usuario, sino más bien la organización de la jerarquía visual de la aplicación.These objects don't represent any user interface, but rather the organization of the application's visual hierarchy. Shell tomará estos elementos y generará la interfaz de usuario de navegación del contenido.Shell will take these objects and produce the navigation user interface for the content. Por lo tanto, la clase AppShell define dos páginas que se pueden navegar desde las pestañas inferiores.Therefore, the AppShell class defines defines two pages that are navigable from bottom tabs. Las páginas se crean a petición, en respuesta a la navegación del usuario.The pages are created on demand, in response to user navigation.

Para más información sobre las aplicaciones de Shell, consulte Xamarin.Forms Shell.For more information about Shell applications, see Xamarin.Forms Shell.

Interfaz de usuarioUser interface

Existen varios grupos de controles que se usan para crear la interfaz de usuario de una aplicación de Xamarin.Forms:There are several control groups used to create the user interface of a Xamarin.Forms application:

  1. Páginas: las páginas de Xamarin.Forms representan pantallas de aplicaciones móviles multiplataforma.Pages – Xamarin.Forms pages represent cross-platform mobile application screens. En la aplicación Notes se usa la clase ContentPage para mostrar pantallas únicas.The Notes application uses the ContentPage class to display single screens. Para obtener más información sobre las páginas de códigos, vea Páginas de Xamarin.Forms.For more information about pages, see Xamarin.Forms Pages.
  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.Views – Xamarin.Forms views are the controls displayed on the user interface, such as labels, buttons, and text entry boxes. En la aplicación Notes terminada se usan las vistas CollectionView, Editor y Button.The finished Notes application uses the CollectionView, Editor, and Button views. Para obtener más información sobre las vistas, consulte Vistas de Xamarin.Forms.For more information about views, see Xamarin.Forms Views.
  3. Diseños: los diseños de Xamarin.Forms son contenedores que se usan para crear vistas en estructuras lógicas.Layouts – Xamarin.Forms layouts are containers used to compose views into logical structures. 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.The Notes application uses the StackLayout class to arrange views in a vertical stack, and the Grid class to arrange buttons horizontally. Para obtener más información sobre los diseños, consulte Diseños de Xamarin.Forms.For more information about layouts, see Xamarin.Forms Layouts.

En tiempo de ejecución, cada control se asignará a su equivalente nativo, que es lo que se representará.At runtime, each control will be mapped to its native equivalent, which is what will be rendered.

DiseñoLayout

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.The Notes application uses the StackLayout to simplify cross-platform application development by automatically arranging views on the screen regardless of the screen size. Cada elemento secundario se coloca uno detrás del otro, ya sea horizontal o verticalmente, en el orden en el que se ha agregado.Each child element is positioned one after the other, either horizontally or vertically in the order they were added. 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.How much space the StackLayout will use depends on how the HorizontalOptions and VerticalOptions properties are set, but by default the StackLayout will try to use the entire screen.

En el código XAML siguiente se muestra un ejemplo de uso de una clase StackLayout para organizar el control NoteEntryPage:The following XAML code shows an example of using a StackLayout to layout the 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.By default the StackLayout assumes a vertical orientation. Pero se puede cambiar a una orientación horizontal si se establece la propiedad StackLayout.Orientation en el miembro de enumeración StackOrientation.Horizontal.However, it can be changed to a horizontal orientation by setting the StackLayout.Orientation property to the StackOrientation.Horizontal enumeration member.

Nota

El tamaño de las vistas se puede establecer a través de las propiedades HeightRequest y WidthRequest.The size of views can be set through the HeightRequest and WidthRequest properties.

Para más información sobre la clase StackLayout, consulte Xamarin.Forms StackLayout.For more information about the StackLayout class, see Xamarin.Forms StackLayout.

Responder a la interacción del usuarioResponding to user interaction

Un objeto que se ha definido en XAML puede desencadenar un evento que se controla en el archivo de código subyacente.An object defined in XAML can fire an event that is handled in the code-behind file. 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.The following code example shows the OnSaveButtonClicked method in the code-behind for the NoteEntryPage class, which is executed in response to the Clicked event firing on the Save button.

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.The OnSaveButtonClicked method saves the note in the database, and navigates back to the previous page. Para más información sobre la navegación, consulte Navegación.For more information about navigation, see Navigation.

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.The code-behind file for a XAML class can access an object defined in XAML using the name assigned to it with the x:Name attribute. 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.The value assigned to this attribute has the same rules as C# variables, in that it must begin with a letter or underscore and contain no embedded spaces.

La conexión del botón Guardar con el método OnSaveButtonClicked se realiza en el marcado XAML de la clase NoteEntryPage:The wiring of the save button to the OnSaveButtonClicked method occurs in the XAML markup for the NoteEntryPage class:

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

ListasLists

CollectionView es responsable de mostrar una colección de elementos en una lista.The CollectionView is responsible for displaying a collection of items in a list. De manera predeterminada, los elementos de la lista se muestran verticalmente y cada elemento se muestra en una sola fila.By default, list items are displayed vertically and each item is displayed in a single row.

En el ejemplo de código siguiente se muestra el elemento CollectionView de NotesPage:The following code example shows the CollectionView from the 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.The layout of each row in the CollectionView is defined within the CollectionView.ItemTemplate element, and uses data binding to display any notes that are retrieved by the application. La propiedad CollectionView.ItemsSource está establecida en el origen de datos, en NotesPage.xaml.cs:The CollectionView.ItemsSource property is set to the data source, in 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.This code populates the CollectionView with any notes stored in the database, and is executed when the page appears.

Cuando se selecciona un elemento en CollectionView, se desencadena el evento SelectionChanged.When an item is selected in the CollectionView, the SelectionChanged event fires. Cuando se desencadena el evento, se ejecuta un controlador de eventos denominado OnSelectionChanged:An event handler, named OnSelectionChanged, is executed when the event fires:

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.The SelectionChanged event can access the object that was associated with the item through the e.CurrentSelection property.

Para más información sobre la clase CollectionView, consulte Xamarin.Forms CollectionView.For more information about the CollectionView class, see Xamarin.Forms CollectionView.

La navegación se realiza en una aplicación de Shell mediante la especificación de un URI al que navegar.Navigation is performed in a Shell application by specifying a URI to navigate to. Los URI de navegación tienen tres componentes:Navigation URIs have three components:

  • Una ruta, que define la ruta de acceso al contenido que existe como parte de la jerarquía visual de Shell.A route, which defines the path to content that exists as part of the Shell visual hierarchy.
  • Una página.A page. 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.Pages that don't exist in the Shell visual hierarchy can be pushed onto the navigation stack from anywhere within a Shell application. 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.For example, the NoteEntryPage isn't defined in the Shell visual hierarchy, but can be pushed onto the navigation stack as required.
  • Uno o varios parámetros de consulta.One or more query parameters. Los parámetros de consulta son parámetros que se pueden pasar a la página de destino durante la navegación.Query parameters are parameters that can be passed to the destination page while navigating.

No es necesario que un URI de navegación incluya los tres componentes pero, cuando lo hace, la estructura es: //route/page?queryParametersA navigation URI doesn't have to include all three components, but when it does the structure is: //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.Routes can be defined on elements in the Shell visual hierarchy via the Route property. 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.However, if the Route property isn't set, such as in the Notes application, a route is generated at runtime.

Para más información sobre la navegación de Shell, consulte Navegación de Xamarin.Forms Shell.For more information about Shell navigation, see Xamarin.Forms Shell navigation.

Registro de rutasRegister routes

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.To navigate to a page that doesn't exist in the Shell visual hierarchy requires it to first be registered with the Shell routing system. con el método Routing.RegisterRoute.using the Routing.RegisterRoute method. En la aplicación de notas, esto ocurre en el constructor AppShell:In the Notes application, this occurs in the AppShell constructor:

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.In this example, a route named NoteEntryPage is registered against the NoteEntryPage type. Luego, es posible navegar a esta página desde cualquier lugar de la aplicación mediante la navegación basada en el URI.This page can then be navigated to using URI-based navigation, from anywhere in the application.

Realización de la navegaciónPerform navigation

La navegación se realiza mediante el método GoToAsync, que acepta un argumento que representa la ruta a la que navegar:Navigation is performed by the GoToAsync method, which accepts an argument that represents the route to navigate to:

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

En este ejemplo, se navega a NoteEntryPage.In this example, the NoteEntryPage is navigated to.

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.A navigation stack is created when a page that's not in the Shell visual hierarchy is navigated to.

Al navegar a una página, los datos se pueden pasar a la página como un parámetro de consulta:When navigating to a page, data can be passed to the page as a query parameter:

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.This example retrieves the currently selected item in the CollectionView and navigates to the NoteEntryPage, with the value of ID property of the Note object being passed as a query parameter to the NoteEntryPage.ItemId property.

Para recibir los datos pasados, la clase NoteEntryPage se decora con el atributo QueryPropertyAttribute.To receive the passed data, the NoteEntryPage class is decorated with the 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.The first argument for the QueryPropertyAttribute specifies that the ItemId property will receive the passed data, with the second argument specifying the query parameter id. Therefore, the QueryPropertyAttribute in the above example specifies that the ItemId property will receive the data passed in the ItemId query parameter from the URI in the GoToAsync method call. Luego, la propiedad ItemId llama al método LoadNote para recuperar la nota del dispositivo.The ItemId property then calls the LoadNote method to retrieve the note from the device.

La navegación hacia atrás se puede llevar a cabo si especifica ".." como el argumento para el método GoToAsync:Backwards navigation is performed by specifying ".." as the argument to the GoToAsync method:

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

Para más información sobe la navegación hacia atrás, consulte Navegación hacia atrás.For more information about backwards navigation, see Backwards navigation.

Enlace de datosData binding

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.Data binding is used to simplify how a Xamarin.Forms application displays and interacts with its data. Establece una conexión entre la interfaz de usuario y la aplicación subyacente.It establishes a connection between the user interface and the underlying application. La clase BindableObject contiene gran parte de la infraestructura para admitir el enlace de datos.The BindableObject class contains much of the infrastructure to support data binding.

El enlace de datos conecta dos objetos, denominados origen y destino.Data binding connects two objects, called the source and the target. El objeto de origen proporciona los datos.The source object provides the data. El objeto de destino usa (y, a menudo, muestra) los datos del objeto de origen.The target object will consume (and often display) data from the source object. Por ejemplo, un control Editor (objeto de destino) normalmente enlazará su propiedad Text a una propiedad string pública en un objeto de origen.For example, an Editor (target object) will commonly bind its Text property to a public string property in a source object. En el diagrama siguiente se muestra la relación de enlace:The following diagram illustrates the binding relationship:

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.The main benefit of data binding is that you no longer have to worry about synchronizing data between your views and data source. 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.Changes in the source object are automatically pushed to the target object behind-the-scenes by the binding framework, and changes in the target object can be optionally pushed back to the source object.

El establecimiento del enlace de datos es un proceso de dos pasos:Establishing data binding is a two-step process:

  • La propiedad BindingContext del objeto de destino se debe establecer en el de origen.The BindingContext property of the target object must be set to the source.
  • Es necesario establecer un enlace entre el destino y el origen.A binding must be established between the target and the source. En XAML, esto se consigue mediante la extensión de marcado Binding.In XAML, this is achieved by using the Binding markup extension.

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.In the Notes application, the binding target is the Editor that displays a note, while the Note instance set as the BindingContext of NoteEntryPage is the binding source. Inicialmente, BindingContext de NoteEntryPage se establece cuando se ejecuta el constructor de página:Initially, the BindingContext of the NoteEntryPage is set when the page constructor executes:

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

En este ejemplo, el BindingContext de la página está establecido en una Note nueva cuando se crea NoteEntryPage.In this example, the page's BindingContext is set to a new Note when the NoteEntryPage is created. Esto controla el escenario en que se agrega una nota nueva a la aplicación.This handles the scenario of adding a new note to the application.

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:In addition, the page's BindingContext can also be set when navigation to the NoteEntryPage occurs, provided that an existing note was selected on the 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.In this example, when page navigation occurs the page's BindingContext is set to the selected Note object after it's been retrieved from the database.

Importante

Aunque la propiedad BindingContext de cada objeto de destino se puede establecer de manera individual, no es necesario hacerlo.While the BindingContext property of each target object can be individually set, this isn’t necessary. BindingContext es una propiedad especial que heredan todos sus elementos secundarios.BindingContext is a special property that’s inherited by all its children. 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.Therefore, when the BindingContext on the ContentPage is set to a Note instance, all of the children of the ContentPage have the same BindingContext, and can bind to public properties of the Note object.

Después, el objeto Editor de NoteEntryPage se enlaza a la propiedad Text del objeto Note:The Editor in NoteEntryPage then binds to the Text property of the Note object:

<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.A binding between the Editor.Text property and the Text property of the source object is established. Los cambios realizados en Editor se propagarán de forma automática al objeto Note.Changes made in the Editor will automatically be propagated to the Note object. 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.Similarly, if changes are made to the Note.Text property, the Xamarin.Forms binding engine will also update the contents of the Editor. Esto se conoce como enlace bidireccional.This is known as a two-way binding.

Para obtener más información sobre el enlace de datos, consulte Enlace de datos de Xamarin.Forms.For more information about data binding, see Xamarin.Forms Data Binding.

Aplicación de estilosStyling

Las aplicaciones de Xamarin.Forms suelen contener varios elementos visuales que tienen un aspecto idéntico.Xamarin.Forms applications often contain multiple visual elements that have an identical appearance. Establecer la apariencia de cada elemento visual puede ser repetitivo y propenso a errores.Setting the appearance of each visual element can be repetitive and error prone. En su lugar, se pueden crear estilos que definan el aspecto y, después, aplicarlos a los elementos visuales necesarios.Instead, styles can be created that define the appearance, and then applied to the required visual elements.

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.The Style class groups a collection of property values into one object that can then be applied to multiple visual element instances. 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.Styles are stored in a ResourceDictionary, either at the application level, the page level, or the view level. La elección de dónde se puede definir un elemento Style afecta a dónde se puede usar:Choosing where to define a Style impacts where it can be used:

  • Las instancias de Style definidas en el nivel de aplicación se pueden aplicar en toda la aplicación.Style instances defined at the application level can be applied throughout the application.
  • Las instancias de Style definidas en el nivel de página se pueden aplicar a la página y a sus elementos secundarios.Style instances defined at the page level can be applied to the page and to its children.
  • Las instancias de Style definidas en el nivel de vista se pueden aplicar a la vista y a sus elementos secundarios.Style instances defined at the view level can be applied to the view and to its children.

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.Any styles that are used throughout the application are stored in the application's resource dictionary to avoid duplication. 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.However, XAML that's specific to a page shouldn't be included in the application's resource dictionary, as the resources will then be parsed at application startup instead of when required by a page. Para más información, consulte Reducción del tamaño del diccionario de recursos de aplicación.For more information, see Reduce the application resource dictionary size.

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.Each Style instance contains a collection of one or more Setter objects, with each Setter having a Property and a 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.The Property is the name of the bindable property of the element the style is applied to, and the Value is the value that is applied to the property. En el ejemplo de código siguiente se muestra un estilo de NoteEntryPage:The following code example shows a style from 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.This style is applied to any Editor instances on the page.

Al crear un elemento Style, siempre se requiere la propiedad TargetType.When creating a Style, the TargetType property is always required.

Nota

Normalmente, la aplicación de estilo a una aplicación Xamarin.Forms se realiza mediante estilos XAML.Styling a Xamarin.Forms application is traditionally accomplished by using XAML styles. Aun así, Xamarin.Forms también admite aplicar estilo a los elementos visuales mediante hojas de estilo CSS (CSS).However, Xamarin.Forms also supports styling visual elements using Cascading Style Sheets (CSS). Para obtener más información, vea Aplicación de estilos para aplicaciones Xamarin.Forms con hojas de estilo (CSS).For more information, see Styling Xamarin.Forms apps using Cascading Style Sheets (CSS).

Para obtener más información sobre los estilos XAML, vea Aplicación de estilo a aplicaciones Xamarin.Forms con estilos XAML.For more information about XAML styles, see Styling Xamarin.Forms Apps using XAML Styles.

Prueba e implementaciónTest and deployment

Tanto Visual Studio para Mac como Visual Studio ofrecen numerosas opciones para probar e implementar una aplicación.Visual Studio for Mac and Visual Studio both provide many options for testing and deploying an application. 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.Debugging applications is a common part of the application development lifecycle and helps to diagnose code issues. 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).For more information, see Set a Breakpoint, Step Through Code, and Output Information to the Log Window.

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.Simulators are a good place to start deploying and testing an application, and feature useful functionality for testing applications. 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.However, users will not consume the final application in a simulator, so applications should be tested on real devices early and often. Para obtener más información sobre el aprovisionamiento de dispositivos de iOS, consulte Aprovisionamiento de dispositivos.For more information about iOS device provisioning, see Device Provisioning. Para obtener más información sobre el aprovisionamiento de dispositivos de Android, consulte Configurar el dispositivo para el desarrollo.For more information about Android device provisioning, see Set Up Device for Development.

Pasos siguientesNext steps

En este análisis detallado se han examinado los aspectos fundamentales del desarrollo de aplicaciones con Xamarin.Forms Shell.This deep dive has examined the fundamentals of application development using Xamarin.Forms Shell. Se recomienda que, como paso siguiente, lea sobre las funcionalidades que se indican a continuación:Suggested next steps include reading about the following functionality:

  • 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.Xamarin.Forms Shell reduces the complexity of mobile application development by providing the fundamental features that most mobile applications require. Para obtener más información, consulte Xamarin.Forms Shell.For more information, see Xamarin.Forms Shell.
  • Existen varios grupos de controles que se usan para crear la interfaz de usuario de una aplicación de Xamarin.Forms.There are several control groups used to create the user interface of a Xamarin.Forms application. Para obtener más información, vea Referencia de controles.For more information, see Controls Reference.
  • 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.Data binding is a technique for linking properties of two objects so that changes in one property are automatically reflected in the other property. Para obtener más información, vea Enlace de datos.For more information, see Data Binding.
  • Xamarin.Forms ofrece varias experiencias de navegación por páginas, en función del tipo de página que se use.Xamarin.Forms provides multiple page navigation experiences, depending upon the page type being used. Para obtener más información, consulte Navigation (Navegación).For more information, see Navigation.
  • Los estilos permiten reducir el uso de marcado repetitivo y conseguir que la apariencia de las aplicaciones pueda cambiarse con mayor facilidad.Styles help to reduce repetitive markup, and allow an applications appearance to be more easily changed. Para obtener más información, consulte Aplicación de estilos a aplicaciones Xamarin.Forms.For more information, see Styling Xamarin.Forms Apps.
  • Las plantillas de datos permiten definir la presentación de los datos en las vistas admitidas.Data templates provide the ability to define the presentation of data on supported views. Para obtener más información, consulte Data Templates (Plantillas de datos).For more information, see Data Templates.
  • Los efectos también permiten personalizar los controles nativos de cada plataforma.Effects also allow the native controls on each platform to be customized. 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.Effects are created in platform-specific projects by subclassing the PlatformEffect class, and are consumed by attaching them to an appropriate Xamarin.Forms control. Para obtener más información, consulte Effects (Efectos).For more information, see Effects.
  • 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.Each page, layout, and view is rendered differently on each platform using a Renderer class that in turn creates a native control, arranges it on the screen, and adds the behavior specified in the shared code. Los desarrolladores pueden implementar sus propias clases Renderer personalizadas para personalizar la apariencia o el comportamiento de un control.Developers can implement their own custom Renderer classes to customize the appearance and/or behavior of a control. Para obtener más información, consulte Custom Renderers (Representadores personalizados).For more information, see Custom Renderers.
  • El código compartido puede tener acceso a la funcionalidad nativa mediante la clase DependencyService.Shared code can access native functionality through the DependencyService class. Para obtener más información, consulte Accessing Native Features with DependencyService (Acceso a características nativas con DependencyService).For more information, see Accessing Native Features with DependencyService.

Encuentre más vídeos de Xamarin en Channel 9 y YouTube.Find more Xamarin videos on Channel 9 and YouTube.