【Xamarin.Forms】第1部分:XAML入门——用元素和属性定义一个页面

2510阅读 0评论2017-11-19 renxiao2003
分类:Android平台

在Xamarin.Forms应用程序中,XAML主要用于定义页面的可视内容。 一个XAML文件总是与一个C#代码文件相关联,该代码文件为标记提供代码支持。 这两个文件一起构成一个包含子视图和属性初始化的新类定义。 在XAML文件中,类和属性被XML元素和属性引用,并且标记和代码之间的链接被建立。


创建解决方案

要开始编辑您的第一个XAML文件,请使用Visual Studio或Visual Studio for Mac创建一个新的Xamarin.Forms解决方案。 (选择对应于您的环境的页面顶部的选项卡。)
在Windows中,使用Visual Studio从菜单中选择“文件”>“新建”>“项目”。 在“新建项目”对话框中,选择左侧的Visual C#>跨平台,然后从中心列表中选择跨平台应用程序(Xamarin.Forms或Native)

为解决方案选择一个位置,给它一个XamlSamples的名称(或任何您喜欢的),然后按OK。

在下一个屏幕上,选择空白应用程序模板,Xamarin.Forms UI技术和便携式类库(PCL)代码共享策略:

按OK。

解决方案中创建了四个项目:XamlSamples可移植类库(PCL),XamlSamples.Android,XamlSamples.iOS和通用Windows平台解决方案XamlSamples.UWP。

在创建XamlSamples解决方案之后,您可能希望通过选择各种平台项目作为解决方案启动项目来测试开发环境,并在手机模拟器或实际设备上构建和部署由项目模板创建的简单应用程序。

除非需要编写特定于平台的代码,否则共享的XamlSamples PCL项目就是您几乎花费所有编程时间的地方。 这些文章不会冒险在这个项目之外。

XAML文件的解剖

在XamlSamples可移植类库中有一对文件,其名称如下:

您需要单击App.xaml旁边的箭头以查看代码隐藏文件。

App.xaml和App.xaml.cs都有助于派生自Application的名为App的类。 大多数其他具有XAML文件的类都有助于派生自ContentPage的类; 这些文件使用XAML来定义整个页面的可视内容。 XamlSamples项目中的其他两个文件也是如此:

MainPage.xaml文件如下所示:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              xmlns:local="clr-namespace:XamlSamples"
  4.              x:Class="XamlSamples.MainPage">

  5.     <Label Text="Welcome to Xamarin Forms!"
  6.            VerticalOptions="Center"
  7.            HorizontalOptions="Center" />

  8. </ContentPage>


两个XML名称空间(xmlns)声明引用了URI,第一个看起来在Xamarin网站上,第二个在微软。不要麻烦检查这些URI指向什么。那里什么都没有它们只是Xamarin和Microsoft拥有的URI,它们基本上是作为版本标识符的。

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

本地名称空间声明允许您访问PCL项目中的其他类。

在第一个标签的末尾,x前缀用于名为Class的属性。因为这个x前缀的使用对于XAML命名空间来说实际上是通用的,所以像XAML这样的XAML属性几乎总是被称为x:Class。


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

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

MainPage.xaml.cs文件看起来像这样(除了未使用的使用指令):

点击(此处)折叠或打开

  1. using Xamarin.Forms;

  2. namespace XamlSamples
  3. {
  4.     public partial class MainPage : ContentPage
  5.     {
  6.         public MainPage()
  7.         {
  8.             InitializeComponent();
  9.         }
  10.     }
  11. }
MainPage类派生自ContentPage,但注意到部分类定义。这表明对于MainPage应该有另一个部分的类定义,但是它在哪里呢?那InitializeComponent方法是什么?

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

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

尽管您通常不需要花费太多时间来处理生成的代码文件,但是有时会在生成的文件中的代码中引发运行时异常,因此您应该熟悉它们。

当你编译和运行这个程序时,Label元素就像XAML所建议的那样出现在页面的中心。从左到右的三个平台是iOS,Android和Windows 10 Mobile:



对于更有趣的视觉效果,您只需要更有趣的XAML。

测试该程序在继续之前仍然编译和部署。


添加新的XAML页面

要将其他基于XAML的ContentPage类添加到项目中,请选择XamlSamples PCL项目并调用Project> Add New Item菜单项。 在Add New Item对话框的左侧,选择Visual C#和Xamarin.Forms。 从列表中选择内容页面(不是内容页面(C#),它创建一个只有代码的页面,或内容视图,这不是一个页面)。 给页面一个名字,例如HelloXamlPage.xaml:

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

设置页面内容

编辑HelloXamlPage.xaml文件,以便唯一的标签是ContentPage和ContentPage.Content的标签:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="XamlSamples.HelloXamlPage">
  4.     <ContentPage.Content>

  5.     </ContentPage.Content>
  6. </ContentPage>
ContentPage.Content标签是XAML独特语法的一部分。 起初,他们似乎是无效的XML,但他们是合法的。 这段时间不是XML中的特殊字符。

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

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="XamlSamples.HelloXamlPage"
  4.              Title="Hello XAML Page">
  5.     <ContentPage.Content>

  6.         <Label Text="Hello, XAML!"
  7.                VerticalOptions="Center"
  8.                HorizontalTextAlignment="Center"
  9.                Rotation="-15"
  10.                IsVisible="true"
  11.                FontSize="Large"
  12.                FontAttributes="Bold"
  13.                TextColor="Blue" />

  14.     </ContentPage.Content>
  15. </ContentPage>


还要注意在根标签上已经设置了Title属性。

此时,类,属性和XML之间的关系应该是明显的:Xamarin.Forms类(如ContentPage或Label)作为XML元素出现在XAML文件中。该类的属性(包括ContentPage上的Title和Label的七个属性)通常显示为XML属性。

存在许多快捷方式来设置这些属性的值。一些属性是基本的数据类型:例如,Title和Text属性的类型是String,Rotation是Double类型的,而IsVisible(默认情况下是true,在这里只是为了说明而设置)是Boolean类型的。

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

然而,对于更复杂类型的属性,转换器用于解析XAML。这些是从TypeConverter派生的Xamarin.Forms中的类。许多是公开课,但有些不是。对于这个特定的XAML文件,其中的几个类在后台扮演一个角色:


这些转换器管理属性设置的允许语法。

ThicknessTypeConverter可以处理由逗号分隔的一个,两个或四个数字。 如果提供一个号码,则适用于所有四方。 用两个数字,第一个是左右填充,第二个是上下。 四个数字按照左,上,右,下的顺序排列。

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

FontSizeConverter可以处理NamedSize成员或数字字体大小。

ColorTypeConverter接受Color结构的公共静态字段的名称或十六进制RGB值,带有或不带有Alpha通道,前面带有数字符号(#)。 这里是没有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对象:

点击(此处)折叠或打开

  1. public App()
  2. {
  3.     InitializeComponent();
  4.     MainPage = new NavigationPage(new MainPage());
  5. }


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

点击(此处)折叠或打开

  1. public MainPage()
  2. {
  3.     InitializeComponent();

  4.     Button button = new Button
  5.     {
  6.         Text = "Navigate!",
  7.         HorizontalOptions = LayoutOptions.Center,
  8.         VerticalOptions = LayoutOptions.Center
  9.     };

  10.     button.Clicked += async (sender, args) =>
  11.     {
  12.         await Navigation.PushAsync(new HelloXamlPage());
  13.     };

  14.     Content = button;
  15. }
设置页面的Content属性将替换XAML文件中的Content属性的设置。 当您编译和部署该程序的新版本时,屏幕上会出现一个按钮。 按它导航到HelloXamlPage。 以下是iPhone,Android和Windows 10移动设备上的最终页面:



您可以使用iOS上的<返回按钮,使用页面顶部的左侧箭头或Android手机底部的左侧箭头或使用Windows 10 Mobile页面底部的左侧箭头导航回MainPage。

随意尝试使用XAML来呈现标签的不同方式。 如果您需要将任何Unicode字符嵌入到文本中,则可以使用标准的XML语法。 例如,要将问候语放在智能报价中,请使用:



点击(此处)折叠或打开

  1. <Label Text="“Hello, XAML!”"/>


以下是它的样子:

XAML和代码交互

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

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="XamlSamples.XamlPlusCodePage"
  4.              Title="XAML + Code Page">
  5.     <StackLayout>
  6.         <Slider VerticalOptions="CenterAndExpand" />

  7.         <Label Text="A simple Label"
  8.                Font="Large"
  9.                HorizontalOptions="Center"
  10.                VerticalOptions="CenterAndExpand" />

  11.         <Button Text="Click Me!"
  12.                 HorizontalOptions="Center"
  13.                 VerticalOptions="CenterAndExpand" />
  14.     </StackLayout>
  15. </ContentPage>


这个XAML文件在语法上是完整的,下面是它的样子:

但是,您可能会认为该计划在功能上存在缺陷。 也许滑块应该使标签显示当前的值,而按钮可能是打算在程序中做一些事情。

正如您将在第4部分中看到的那样。使用数据绑定基础知识,使用标签显示滑块值的工作完全可以在数据绑定的XAML中处理。 但首先看代码解决方案是有用的。 即使如此,处理按钮点击肯定需要代码。 这意味着XamlPlusCodePage的代码隐藏文件必须包含Slider的ValueChanged事件和Button的Clicked事件的处理程序。 我们来添加它们:

点击(此处)折叠或打开

  1. namespace XamlSamples
  2. {
  3.     public partial class XamlPlusCodePage
  4.     {
  5.         public XamlPlusCodePage()
  6.         {
  7.             InitializeComponent();
  8.         }

  9.         void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
  10.         {

  11.         }

  12.         void OnButtonClicked(object sender, EventArgs args)
  13.         {

  14.         }
  15.     }
  16. }
这些事件处理程序不需要公开。

回到XAML文件中,Slider和Button标签需要包含引用这些处理程序的ValueChanged和Clicked事件的属性:

点击(此处)折叠或打开

  1. <ContentPage xmlns=""
  2.              xmlns:x=""
  3.              x:Class="XamlSamples.XamlPlusCodePage"
  4.              Title="XAML + Code Page">
  5.     <StackLayout>
  6.         <Slider VerticalOptions="CenterAndExpand"
  7.                 ValueChanged="OnSliderValueChanged" />

  8.         <Label Text="A simple Label"
  9.                Font="Large"
  10.                HorizontalOptions="Center"
  11.                VerticalOptions="CenterAndExpand" />

  12.         <Button Text="Click Me!"
  13.                 HorizontalOptions="Center"
  14.                 VerticalOptions="CenterAndExpand"
  15.                 Clicked="OnButtonClicked" />
  16.     </StackLayout>
  17. </ContentPage>
请注意,为事件分配处理程序的方式与为属性分配值的语法相同。

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

点击(此处)折叠或打开

  1. <Label x:Name="valueLabel"
  2.        Text="A simple Label"
  3.        Font="Large"
  4.        HorizontalOptions="Center"
  5.        VerticalOptions="CenterAndExpand" />


x:Name属性的x前缀表示此属性是XAML固有的。

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

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

点击(此处)折叠或打开

  1. void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
  2. {
  3.     valueLabel.Text = args.NewValue.ToString("F3");
  4. }
或者,处理程序可以从sender参数中获取生成此事件的Slider对象,并从中获取Value属性:

点击(此处)折叠或打开

  1. void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
  2. {
  3.     valueLabel.Text = ((Slider)sender).Value.ToString("F3");
  4. }

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



现在为按钮。 让我们通过用按钮的文本显示一个警报模拟对点击事件的响应。 事件处理程序可以安全地将sender参数强制转换为Button,然后访问其属性:

点击(此处)折叠或打开

  1. async void OnButtonClicked(object sender, EventArgs args)
  2. {
  3.     Button button = (Button)sender;
  4.     await DisplayAlert("Clicked!",
  5.         "The button labeled '" + button.Text + "' has been clicked",
  6.         "OK");
  7. }

该方法被定义为async,因为DisplayAlert方法是异步的,应该以await运算符开头,当方法完成时返回。 因为这个方法从发送者参数获得触发事件的Button,所以同一个处理程序可以用于多个按钮。

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

通过检查新生成的XamlPlusCode.xaml.g.cs文件可以搜集到关于XAML如何工作的一些额外信息,该文件现在包含任何分配给任何x:Name属性的名称作为专用字段。 这是该文件的简化版本:

点击(此处)折叠或打开

  1. public partial class XamlPlusCodePage : ContentPage {

  2.     private Label valueLabel;

  3.     private void InitializeComponent() {
  4.         this.LoadFromXaml(typeof(XamlPlusCodePage));
  5.         valueLabel = this.FindByName<Label>("valueLabel");
  6.     }
  7. }


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

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

随意。这是您的页面,而XAML只是构建其内容的工具。


概要

通过这个介绍,您已经看到了XAML文件和代码文件如何对类定义做出贡献,以及XAML和代码文件如何交互。 但是XAML也有其独特的语法功能,可以非常灵活地使用它。 您可以在第2部分开始探索这些内容。基本的XAML语法。


上一篇:【Xamarin.TestCloud】Visual Studio应用程序中心:下一代Xamarin测试云
下一篇:【Xamarin.Forms】第2部分:基本的XAML语法——使用属性元素和附加属性