Carga de XAML en tiempo de ejecución en Xamarin.Forms

El espacio de nombres Xamarin.Forms.Xaml incluye dos métodos de extensión LoadFromXaml que se pueden usar para cargar y analizar XAML en tiempo de ejecución.

Fondo

Cuando se construye una clase XAML Xamarin.Forms, se llama indirectamente al método LoadFromXaml. Esto ocurre porque el archivo de código subyacente de una clase XAML llama al método InitializeComponent desde su constructor:

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

Cuando Visual Studio compila un proyecto que contiene un archivo XAML, analiza el archivo XAML para generar un archivo de código de C# (por ejemplo, MainPage.xaml.g.cs) que contiene la definición del método InitializeComponent:

private void InitializeComponent()
{
    global::Xamarin.Forms.Xaml.Extensions.LoadFromXaml(this, typeof(MainPage));
    ...
}

El método InitializeComponent llama al método LoadFromXaml para extraer el archivo XAML (o su binario compilado) de la biblioteca de .NET Standard. Después de la extracción, 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 código a eventos establecidos en el archivo XAML y establece el árbol resultante de objetos como el contenido de la página.

Carga de XAML en tiempo de ejecución

Los métodos LoadFromXaml son publicy, por tanto, se puede llamar desde aplicaciones Xamarin.Forms para cargar y analizar XAML en tiempo de ejecución. Esto permite escenarios como una aplicación que descarga XAML desde un servicio web, crea la vista necesaria a partir del XAML y la muestra en la aplicación.

Advertencia

La carga de XAML en tiempo de ejecución tiene un coste de rendimiento significativo y, por lo general, se debe evitar.

El siguiente código muestra un ejemplo de uso sencillo:

using Xamarin.Forms.Xaml;
...

string navigationButtonXAML = "<Button Text=\"Navigate\" />";
Button navigationButton = new Button().LoadFromXaml(navigationButtonXAML);
...
_stackLayout.Children.Add(navigationButton);

En este ejemplo, se crea una instancia de Button, con su valor de propiedad Text establecido a partir del XAML definido en string. Después, se agrega Button a un objeto StackLayout que se ha definido en el XAML de la página.

Nota:

Los métodos de extensión LoadFromXaml permiten especificar un argumento de tipo genérico. Sin embargo, rara vez es necesario especificar el argumento de tipo, ya que se deducirá del tipo de la instancia en la que funciona.

El método LoadFromXaml se puede usar para inflar cualquier XAML, con el ejemplo siguiente que infla un objeto ContentPage y luego, navega hacia él:

using Xamarin.Forms.Xaml;
...

// See the sample for the full XAML string
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n</ContentPage>";

ContentPage page = new ContentPage().LoadFromXaml(pageXAML);
await Navigation.PushAsync(page);

Acceso a elementos

Cargar XAML en tiempo de ejecución con el método LoadFromXaml no permite el acceso fuertemente tipado a los elementos XAML que tienen nombres de objeto en tiempo de ejecución especificados (mediante x:Name). No obstante, estos elementos XAML se pueden recuperar mediante el método FindByName y, después, se puede acceder a ellos si es necesario:

// See the sample for the full XAML string
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://xamarin.com/schemas/2014/forms\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n<StackLayout>\n<Label x:Name=\"monkeyName\"\n />\n</StackLayout>\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);

Label monkeyLabel = page.FindByName<Label>("monkeyName");
monkeyLabel.Text = "Seated Monkey";
...

En este ejemplo, se infla el XAML de un objeto ContentPage. Este XAML incluye un objeto Label denominado monkeyName, que se recupera mediante el método FindByName, antes de establecer su propiedad Text.