Xamarin.Forms在应用程序中,XAML 主要用于定义页面的视觉内容,并与 C# 代码隐藏文件协同工作。

代码隐藏文件为标记提供代码支持。 这两个文件共同为包含子视图和属性初始化的新类定义做出贡献。 在 XAML 文件中,类和属性使用 XML 元素和属性引用,并建立标记和代码之间的链接。

创建解决方案

若要开始编辑第一个 XAML 文件,请使用Visual Studio或Visual Studio for Mac创建新的Xamarin.Forms解决方案。 (选择与环境对应的选项卡。)

在 Windows 中,启动 Visual Studio 2019,然后在开始窗口中单击“ 创建新项目 ”以创建新项目:

在“创建新项目”窗口中,在“项目类型”下拉菜单中选择“移动”,选择“移动应用(Xamarin.Forms)”,然后单击“下一步”按钮:

“配置新项目 ”窗口中,将 Project名称 设置为 XamlSamples (或任何首选) ,然后单击“ 创建 ”按钮。

在“ 新建跨平台应用 ”对话框中,单击“ 空白 ”,然后单击“ 确定 ”按钮:

解决方案中创建四个项目: XamlSamples .NET Standard 库、 XamlSamples.Android XamlSamples.iOS 和 通用 Windows 平台 解决方案 XamlSamples.UWP

在Visual Studio for Mac中,从菜单中选择 “文件>新建解决方案 ”。 在“ 新建Project ”对话框中,从模板列表中选择 “多平台>应用 ”,从模板列表中选择 “空白窗体应用 ” ( notForms App ) :

按“下一步”。

在下一个对话框中,为项目命名 XamlSamples (或任何首选) 的名称。 确保选中了 “使用 .NET Standard ”单选按钮:

按“下一步”。

在以下对话框中,可以选择项目的位置:

Create

解决方案中创建三个项目: XamlSamples .NET Standard 库、 XamlSamples.Android XamlSamples.iOS

创建 XamlSamples 解决方案后,可能需要选择各种平台项目作为解决方案启动项目来测试开发环境,并在手机仿真器或实际设备上生成和部署项目模板创建的简单应用程序。

除非需要编写特定于平台的代码,否则共享 的 XamlSamples .NET Standard 库项目将花费几乎全部编程时间。 这些文章不会冒险在该项目之外。

XAML 文件的剖析

XamlSamples .NET Standard 库中有一对具有以下名称的文件:

  • App.xaml,XAML 文件;和
  • App.xaml.cs ,一个与 XAML 文件关联的 C# 代码隐藏 文件。
  • 需要单击 App.xaml 旁边的箭头才能查看代码隐藏文件。

    App.xaml App.xaml.cs 都参与派生自 Application 的类 App 。 具有 XAML 文件的大多数其他类都有助于派生自 ContentPage 的类;这些文件使用 XAML 定义整个页面的视觉内容。 这适用于 XamlSamples 项目中的其他两个文件:

  • MainPage.xaml,XAML 文件;和
  • MainPage.xaml.cs ,C# 代码隐藏文件。
  • MainPage.xaml 文件如下所示 (,尽管格式可能略有不同) :

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:XamlSamples"
                 x:Class="XamlSamples.MainPage">
        <StackLayout>
            <!-- Place new controls here -->
            <Label Text="Welcome to Xamarin Forms!"
                   VerticalOptions="Center"
                   HorizontalOptions="Center" />
        </StackLayout>
    </ContentPage>
    

    这两个 XML 命名空间 (xmlns) 声明是指 URI,第一个似乎位于 Xamarin 的网站上,第二个在 Microsoft 网站上。 不要费心检查这些 URI 指向的内容。 没有什么可去的。 它们只是 Xamarin 和 Microsoft 拥有的 URI,它们基本上充当版本标识符。

    第一个 XML 命名空间声明意味着在 XAML 文件中定义的标记没有前缀,例如ContentPage,引用类Xamarin.Forms。 第二个命名空间声明定义前缀 x。 这用于 XAML 本身固有的多个元素和属性,这些元素和属性由 XAML 的其他实现支持。 但是,根据 URI 中嵌入的年份,这些元素和属性略有不同。 Xamarin.Forms 支持 2009 XAML 规范,但并非全部。

    命名空间 local 声明允许从 .NET Standard 库项目访问其他类。

    在第一个标记的末尾,前缀 x 用于名为 Class的属性。 由于此 x 前缀的用法几乎适用于 XAML 命名空间,因此 Class 几乎总是称为 x:ClassXAML 属性。

    x:Class 属性指定完全限定的 .NET 类名: MainPage 命名空间中的 XamlSamples 类。 这意味着,此 XAML 文件定义一个名为命名空间的新类,该类MainPageXamlSamples派生自ContentPage该属性的标记x:Class

    x:Class 属性只能显示在 XAML 文件的根元素中,以定义派生的 C# 类。 这是 XAML 文件中唯一定义的新类。 XAML 文件中出现的其他所有内容只是从现有类实例化并初始化。

    MainPage.xaml.cs 文件类似于此 (,除了未使用的using指令) :

    using Xamarin.Forms;
    namespace XamlSamples
        public partial class MainPage : ContentPage
            public MainPage()
                InitializeComponent();
    

    MainPage 派生自 ContentPage,但请注意 partial 类定义。 这表明应该有 MainPage另一个分部类定义,但它在哪里? 此方法是什么 InitializeComponent

    Visual Studio生成项目时,它会分析 XAML 文件以生成 C# 代码文件。 如果查看 XamlSamples\XamlSamples\obj\Debug 目录,你将找到名为 XamlSamples.MainPage.xaml.g.cs 的文件。 “g”表示生成的。 这是另一个分部类定义MainPage,其中包含从MainPage构造函数调用的方法的定义InitializeComponent。 然后,可以一起编译这两个分部 MainPage 类定义。 根据 XAML 是编译还是未编译 XAML 文件,XAML 文件或 XAML 文件的二进制格式都嵌入到可执行文件中。

    在运行时,特定平台项目中的代码调用方法 LoadApplication ,并将其传递给 .NET Standard 库中类的新实例 App 。 类 App 构造函数实例化 MainPage。 该类调用 InitializeComponent的构造函数,然后调用 LoadFromXaml 从 .NET Standard 库提取 XAML 文件 (或其编译的二进制) 的方法。 LoadFromXaml 初始化 XAML 文件中定义的所有对象,将它们全部连接在父子关系中,将代码中定义的事件处理程序附加到 XAML 文件中设置的事件,并将对象的结果树设置为页面的内容。

    虽然通常不需要花费大量时间处理生成的代码文件,但有时在生成的文件中的代码上引发运行时异常,因此你应该熟悉它们。

    编译并运行此程序时, Label 元素会显示在页面中心,XAML 建议:

    对于更有趣的视觉对象,只需要更有趣的 XAML。

    添加新的 XAML 页面

    Visual Studio Visual Studio for Mac

    将两个文件添加到项目中, HelloXamlPage.xaml 和代码隐藏文件 HelloXamlPage.xaml.cs

    设置页面内容

    编辑 HelloXamlPage.xaml 文件,以便唯一的标记是用于 ContentPageContentPage.Content

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="XamlSamples.HelloXamlPage">
        <ContentPage.Content>
        </ContentPage.Content>
    </ContentPage>
    

    标记 ContentPage.Content 是 XAML 的唯一语法的一部分。 起初,它们似乎是无效的 XML,但它们是合法的。 句点不是 XML 中的特殊字符。

    标记 ContentPage.Content 称为 属性元素 标记。 Content 是一个属性 ContentPage,通常设置为具有子视图的单个视图或布局。 通常,属性成为 XAML 中的属性,但很难将属性 Content 设置为复杂对象。 因此,该属性表示为由类名和由句点分隔的属性名称组成的 XML 元素。 现在可以在 Content 标记之间 ContentPage.Content 设置属性,如下所示:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="XamlSamples.HelloXamlPage"
                 Title="Hello XAML Page">
        <ContentPage.Content>
            <Label Text="Hello, XAML!"
                   VerticalOptions="Center"
                   HorizontalTextAlignment="Center"
                   Rotation="-15"
                   IsVisible="true"
                   FontSize="Large"
                   FontAttributes="Bold"
                   TextColor="Blue" />
        </ContentPage.Content>
    </ContentPage>
    

    另请注意,已在根标记上设置属性 Title

    此时,类、属性和 XML 之间的关系应很明显:类 Xamarin.Forms ((如 ContentPageLabel) )以 XML 元素的形式出现在 XAML 文件中。 该类的属性(包括 Title on ContentPage 和 7 个属性 Label)通常显示为 XML 属性。

    存在许多快捷方式来设置这些属性的值。 某些属性是基本数据类型:例如,Title属性的类型、类型、类型DoubleRotationStringIsVisible ,默认情况下为 (true,此处仅设置为图示) 的类型。BooleanText

    HorizontalTextAlignment 属性的类型 TextAlignment为枚举。 对于任何枚举类型的属性,需要提供的所有属性都是成员名称。

    但是,对于更复杂的类型的属性,转换器用于分析 XAML。 这些类 Xamarin.Forms 派生自 TypeConverter. 许多人是公共类,但有些不是。 对于此特定 XAML 文件,其中几个类在后台发挥作用:

  • LayoutOptionsConverter属性的VerticalOptions
  • FontSizeConverter属性的FontSize
  • ColorTypeConverter属性的TextColor
  • 这些转换器控制属性设置的允许语法。

    可以 ThicknessTypeConverter 处理用逗号分隔的一个、两个或四个数字。 如果提供了一个数字,则适用于所有四面。 使用两个数字,第一个是左填充和右填充,第二个是顶部和底部。 四个数字按左、上、右和下的顺序排列。

    可以将 LayoutOptionsConverter 结构的公共静态字段 LayoutOptions 的名称转换为类型的 LayoutOptions值。

    可以 FontSizeConverter 处理 NamedSize 成员或数字字号。

    接受 ColorTypeConverter 结构或十六进制 RGB 值的公共静态字段 Color 的名称,其前面是数字符号 (#) 。 下面是没有 alpha 通道的语法:

    TextColor="#rrggbb"

    每个小字母都是十六进制数字。 下面介绍了如何包括 alpha 通道:

    TextColor="#aarrggbb">

    对于 alpha 通道,请记住 FF 完全不透明,00 完全透明。

    另外两种格式只允许为每个通道指定一个十六进制数字:

    TextColor="#rgb" TextColor="#argb"

    在这些情况下,将重复数字以形成值。 例如,#CF3是 RGB 颜色 CC-FF-33。

    运行 XamlSamples 程序时,将显示该 MainPage 程序。 若要查看新 HelloXamlPage 内容,可以将其设置为 App.xaml.cs 文件中的新启动页,也可以从 MainPage中导航到新页面。

    若要实现导航,请先更改 App.xaml.cs 构造函数中的代码, NavigationPage 以便创建对象:

    public App()
        InitializeComponent();
        MainPage = new NavigationPage(new MainPage());
    

    MainPage.xaml.cs 构造函数中,可以创建一 Button 个简单的函数,并使用事件处理程序导航到 HelloXamlPage

    public MainPage()
        InitializeComponent();
        Button button = new Button
            Text = "Navigate!",
            HorizontalOptions = LayoutOptions.Center,
            VerticalOptions = LayoutOptions.Center
        button.Clicked += async (sender, args) =>
            await Navigation.PushAsync(new HelloXamlPage());
        Content = button;
    

    Content设置页面的属性将替换 XAML 文件中属性的设置Content。 编译并部署此程序的新版本时,屏幕上会显示一个按钮。 按它导航到 HelloXamlPage。 下面是 iPhone、Android 和 UWP 上的结果页面:

    可以使用 iOS 上的“后退”按钮导航回MainPage<去,使用页面顶部或 Android 手机底部的向左箭头,或使用Windows 10页面上顶部的向左箭头。

    可以随意试验 XAML,以便以不同的方式呈现 。Label 如果需要将任何 Unicode 字符嵌入文本中,可以使用标准 XML 语法。 例如,若要将问候语置于智能引号中,请使用:

    <Label Text="&#x201C;Hello, XAML!&#x201D;" … />

    如下所示:

    XAML 和代码交互

    HelloXamlPage 示例仅包含页面上的单个Label示例,但这非常罕见。 大多数 ContentPage 派生类将 Content 属性设置为某种类型的布局,例如 StackLayoutStackLayout属性Children定义为类型,但它实际上是一个类型的IList<View>ElementCollection<View>对象,并且该集合可以填充多个视图或其他布局。 在 XAML 中,这些父子关系是使用普通 XML 层次结构建立的。 下面是名为 XamlPlusCodePage 的新页面的 XAML 文件:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="XamlSamples.XamlPlusCodePage"
                 Title="XAML + Code Page">
        <StackLayout>
            <Slider VerticalOptions="CenterAndExpand" />
            <Label Text="A simple Label"
                   Font="Large"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand" />
            <Button Text="Click Me!"
                    HorizontalOptions="Center"
                    VerticalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage>
    

    此 XAML 文件语法完整,如下所示:

    但是,你可能认为此程序功能不足。 也许 Slider 这应该导致 Label 显示当前值,并且 Button 可能打算在程序中执行某些操作。

    如第 4 部分所示。数据绑定基础知识,可以使用数据绑定在 XAML 中完全处理使用Label值的工作Slider。 但首先查看代码解决方案非常有用。 即便如此,处理 Button 单击肯定需要代码。 这意味着,必须包含事件的处理程序和Clicked事件的Button代码ValueChangedSlider隐藏文件XamlPlusCodePage。 让我们添加它们:

    namespace XamlSamples
        public partial class XamlPlusCodePage
            public XamlPlusCodePage()
                InitializeComponent();
            void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
            void OnButtonClicked(object sender, EventArgs args)
    

    这些事件处理程序不需要是公共的。

    回到 XAML 文件中, Slider 标记 Button 需要包括引用这些处理程序的属性 ValueChangedClicked 事件:

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="XamlSamples.XamlPlusCodePage"
                 Title="XAML + Code Page">
        <StackLayout>
            <Slider VerticalOptions="CenterAndExpand"
                    ValueChanged="OnSliderValueChanged" />
            <Label Text="A simple Label"
                   Font="Large"
                   HorizontalOptions="Center"
                   VerticalOptions="CenterAndExpand" />
            <Button Text="Click Me!"
                    HorizontalOptions="Center"
                    VerticalOptions="CenterAndExpand"
                    Clicked="OnButtonClicked" />
        </StackLayout>
    </ContentPage>
    

    请注意,将处理程序分配给事件具有与向属性分配值相同的语法。

    如果事件的Slider处理程序ValueChanged将使用Label显示当前值,则处理程序需要从代码中引用该对象。 需要 Label 一个名称,该名称是使用 x:Name 特性指定的。

    <Label x:Name="valueLabel"
           Text="A simple Label"
           Font="Large"
           HorizontalOptions="Center"
           VerticalOptions="CenterAndExpand" />
    

    属性 xx:Name 前缀指示此属性是 XAML 固有的。

    分配给 x:Name 该属性的名称与 C# 变量名称具有相同的规则。 例如,它必须以字母或下划线开头,并且不包含嵌入空格。

    现在, ValueChanged 事件处理程序可以设置 Label 显示新 Slider 值。 新值可从事件参数获取:

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        valueLabel.Text = args.NewValue.ToString("F3");
    

    或者,处理程序可以从自变量获取 Slider 生成此事件 sender 的对象,并从该参数获取 Value 属性:

    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
        valueLabel.Text = ((Slider)sender).Value.ToString("F3");
    

    首次运行程序时, Label 不会显示 Slider 值,因为 ValueChanged 事件尚未触发。 但是, Slider 任何操作都会导致显示值:

    现在为 Button. 让我们通过显示带有按钮的警报Text来模拟对事件的响应Clicked。 事件处理程序可以安全地将 sender 参数强制转换为参数 Button ,然后访问其属性:

    async void OnButtonClicked(object sender, EventArgs args)
        Button button = (Button)sender;
        await DisplayAlert("Clicked!",
            "The button labeled '" + button.Text + "' has been clicked",
            "OK");
    

    该方法被定义为 async 异步 DisplayAlert 方法,并且应以 await 运算符开头,该方法在方法完成时返回。 由于此方法从sender参数中获取Button激发事件,因此同一处理程序可用于多个按钮。

    你已看到 XAML 中定义的对象可以触发在代码隐藏文件中处理的事件,并且代码隐藏文件可以使用分配给该 x:Name 对象的名称访问 XAML 中定义的对象以及该属性。 这是代码和 XAML 交互的两种基本方法。

    通过检查新生成的 XamlPlusCode.xaml.g.cs 文件(现在包括将分配给任何属性的任何 x:Name 名称作为专用字段)来收集 XAML 工作原理的其他一些见解。 下面是该文件的简化版本:

    public partial class XamlPlusCodePage : ContentPage {
        private Label valueLabel;
        private void InitializeComponent() {
            this.LoadFromXaml(typeof(XamlPlusCodePage));
            valueLabel = this.FindByName<Label>("valueLabel");
    

    此字段的声明允许变量在管辖范围内的分部类文件中任意位置 XamlPlusCodePage 自由使用。 在运行时,在分析 XAML 后分配字段。 这意味着该valueLabel字段是在null构造函数开始但调用后InitializeComponent有效的时XamlPlusCodePage

    返回控件返回到构造函数后 InitializeComponent ,页面的视觉对象已构造,就像在代码中实例化和初始化它们一样。 XAML 文件不再在类中扮演任何角色。 你可以以任何方式操作页面上的这些对象,例如,通过将视图添加到 StackLayout页面或将页面的属性完全设置为 Content 其他内容。 可以通过检查 Content 页面的属性和布局集合中的 Children 项来“走树”。 可以设置以这种方式访问的视图的属性,或动态为其分配事件处理程序。

    随意。 它是页面,XAML 只是生成其内容的工具。

    通过本简介,你已了解 XAML 文件和代码文件如何参与类定义,以及 XAML 和代码文件如何交互。 但 XAML 也有自己的独特的语法功能,允许它以非常灵活的方式使用。 可以在第 2 部分开始探索这些 内容。基本 XAML 语法

  • XamlSamples
  • 第 2 部分。 基本 XAML 语法
  • 第 3 部分。 XAML 标记扩展
  • 第 4 部分。 数据绑定基础知识
  • 第 5 部分。 从数据绑定到 MVVM
  •