在 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 包括一个名为 monkeyName
的 Label
,这是在设置其 Text
属性之前使用 FindByName
方法检索的。