Carregando XAML em tempo de execução em Xamarin.Forms

O Xamarin.Forms.Xaml namespace inclui dois LoadFromXaml métodos de extensão que podem ser usados para carregar e analisar XAML em tempo de execução.

Tela de fundo

Quando uma Xamarin.Forms classe XAML é construída, o LoadFromXaml método é chamado indiretamente. Isso ocorre porque o arquivo code-behind para uma classe XAML chama o InitializeComponent método de seu construtor:

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

Quando o Visual Studio cria um projeto que contém um arquivo XAML, ele analisa o arquivo XAML para gerar um arquivo de código C# (por exemplo, MainPage.xaml.g.cs) que contém a definição do InitializeComponent método:

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

O InitializeComponent método chama o LoadFromXaml método para extrair o arquivo XAML (ou seu binário compilado) da biblioteca .NET Standard. Após a extração, ele inicializa todos os objetos definidos no arquivo XAML, conecta-os todos juntos em relações pai-filho, anexa manipuladores de eventos definidos no código a eventos definidos no arquivo XAML e define a árvore resultante de objetos como o conteúdo da página.

Carregando XAML em tempo de execução

Os LoadFromXaml métodos são publice, portanto, podem ser chamados de aplicativos para carregar e analisar XAML em tempo de Xamarin.Forms execução. Isso permite cenários como um aplicativo baixando XAML de um serviço Web, criando a exibição necessária a partir do XAML e exibindo-a no aplicativo.

Aviso

O carregamento de XAML em tempo de execução tem um custo de desempenho significativo e, geralmente, deve ser evitado.

O exemplo de código a seguir mostra um uso simples:

using Xamarin.Forms.Xaml;
...

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

Neste exemplo, uma Button instância é criada, com seu Text valor de propriedade sendo definido a partir do XAML definido no string. O Button é então adicionado a um StackLayout que foi definido no XAML para a página.

Observação

Os LoadFromXaml métodos de extensão permitem que um argumento de tipo genérico seja especificado. No entanto, raramente é necessário especificar o argumento type, pois ele será inferido a partir do tipo da instância em que está operando.

O LoadFromXaml método pode ser usado para inflar qualquer XAML, com o exemplo a seguir inflando um ContentPage e navegando até ele:

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);

Acessando elementos

Carregar XAML em tempo de execução com o LoadFromXaml método não permite acesso fortemente tipado aos elementos XAML que especificaram nomes de objeto de tempo de execução (usando x:Name). No entanto, esses elementos XAML podem ser recuperados usando o FindByName método e, em seguida, acessados conforme necessário:

// 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";
...

Neste exemplo, o XAML para um ContentPage é inflado. Esse XAML inclui um Label , monkeyNamenomeado que é recuperado usando o FindByName método, antes que sua Text propriedade seja definida.