在 Xamarin.Forms 中在运行时加载 XAML

Xamarin.Forms.Xaml 命名空间包括两个可用于在运行时加载和分析 XAML 的 LoadFromXaml 扩展方法。

背景

构造 Xamarin.Forms XAML 类时,将间接调用 LoadFromXaml 方法。 之所以发生这种情况,是因为 XAML 类的代码隐藏文件从其构造函数调用 InitializeComponent 方法:

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

当 Visual Studio 构建包含 XAML 文件的项目时,它将分析该 XAML 文件以生成包含 InitializeComponent 方法的定义的 C# 代码文件(例如,MainPage.xaml.g.cs):

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

InitializeComponent 方法调用 LoadFromXaml 方法来从 .NET Standard 库中提取 XAML 文件(或其编译后的二进制文件)。 在提取后,它将初始化 XAML 文件中定义的所有对象,将它们按父子关系连接在一起,将代码中定义的事件处理程序附加到 XAML 文件中设置的事件,并将得到的对象树设置为页面的内容。

在运行时加载 XAML

LoadFromXaml 方法为 public 方法,因此可以从 Xamarin.Forms 应用程序调用它们以在运行时加载和分析 XAML。 这可以用于实现如下所述的方案:通过 Web 服务下载 XAML,通过 XAML 创建所需视图并在应用程序中显示该视图。

警告

在运行时加载 XAML 会带来很大的性能成本,通常应避免这种情况。

以下代码示例演示了一种简单的用法:

using Xamarin.Forms.Xaml;
...

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

此示例中创建了一个 Button 实例,其 Text 属性值根据 string 中定义的 XAML 进行设置。 然后,将 Button 添加到已在页面的 XAML 中定义的 StackLayout

注意

LoadFromXaml 扩展方法允许指定泛型类型参数。 但是,很少需要指定类型参数,因为将根据该参数所操作的实例的类型来推断该参数。

LoadFromXaml 方法可用于扩充任何 XAML,以下示例将扩展并导航到 ContentPage

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

访问元素

使用 LoadFromXaml 方法在运行时加载 XAML 不允许对已指定了运行时对象名称(使用 x:Name)的 XAML 元素进行强类型访问。 但是,可以使用 FindByName 方法检索这些 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<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";
...

在此示例中,扩充了 ContentPage 的 XAML。 此 XAML 包括一个名为 monkeyNameLabel,这是在设置其 Text 属性之前使用 FindByName 方法检索的。