Xamarin.Forms移动开发系列4 :XAML基础

摘要 本文介绍Xamarin.Forms创建用户界面的语言:XAML基础部分。

前言

本文介绍Xamarin.Forms定义用户界面的语言:XAML。

本篇篇幅较长,主要讲述XAML语法,以及对其他基础知识的粗略认识,后续会分篇探索XAML中的几个重点知识。

大纲

1.XAML概述

2.初始XAML

3.基础语法(重点讲述)

4.标记扩展

5.数据绑定

内容

1.XAML概述

XAML是一种基于XML语言,由微软创建的实例化对象的代码,并组织这些对象的父子级关系,主要应用在WPF、Silverlight、Xamarin.Forms等。

开发人员可以在XAML文件中使用Xamarin.Forms提供的视图、布局和页面来创建用户界面。

XAML文件可以编译,也可以嵌入到可执行文件中。无论哪种方法,XAML代码信息都会在构建时解析,并在运行时再次解析以实例化和初始化对象,以及在这些对象和编程代码之间建立连接。

XAML优势:

● 相比C#代码更简洁易读

● XAML中的父子级关系能够轻松模拟用户界面对象的父子层次结构。

● 能够借助可视化设计工具进行工具化和生成。(Xamarin.Forms暂时没有可视化工具,必须手动编写)

XAML缺点:

● 不能包含事件代码。

● 不能包含多重循环(各别控件除外)。

●  不能包含条件处理。

2.初识XAML

在Xamarin.Forms应用程序中,XAML主要用于定义页面的可视内容,并与Code-Behind文件一起工作。

下面是MainPage.xaml的内容:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">

<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin Forms!"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>

</ContentPage>

首先,声明了三个命名空间(xmlns)

第一个命名空间指向是Xamarin的网站,这意味着在xmln文件中不带任何前缀的标签使用的是Xamarin.Forms中的类,如<ContentPage>、<StackLayout>。

第二个命名空间指向是Microsoft的网站,声明了x的前缀,这意味着带x的标签使用的是xaml本身固有的元素和属性,如:x:Class="App1.MainPage"的属性,使得该xaml文件在App1命名空间下定义了一个MainPage类。

第三个命名空间指向的当前的.NET Standard库App1,这意味着带local前缀的标签使用的是.NET Standard库App1中的类。

往下的代码就是放置一些控件并设置属性。

上述代码创建了一个StackLayout的布局控件,在这个控件内又创建了一个Label文本控件,设置属性Text(文本内容)为“Welcome to Xamarin Forms”,并且设置为水平和垂直居中。

下面是MainPage.xaml.cs的内容:


using Xamarin.Forms;

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

MainPage是一个partial类,这意味着还有另一个分部类的定义,而MainPage构造函数中调用的InitializeComponent方法正是该分部类的一个方法,该方法又调用LoadFromXaml方法从.NET Standard库中加载的XAML文件,初始化xaml文件中的定义的所有对象,将C#代码中的事件处理程序附加到xmal文件中设置的事件,然后设置成页面内容。

可以简单理解为InitializeComponent方法就是初始化xaml界面的。

注:上述分部类是在Visual Studio生成项目是自动生成的,在项目的obj/debug目录下可以找到一个名为MainPage.xaml.g.cs的文件,该文件就是MainPage的分部类。

3.基础语法

3.1 元素和属性

XAML通过XML元素和属性来实例化对象,如:

<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
TextColor="Red"/>
</StackLayout>

Label是Xamarin.Forms对象,在XAML代码中使用XML元素来表示。

HorizontalOptions、VerticalOptions、TextColor是Xamarin.Forms属性,在XAML代码中使用XML元素的属性来表示。

3.2 属性元素

在XAML中某些属性不能简单的用字符串来表示(比如后文提到的内容属性),这时候就需要用到属性元素,如:

<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<!--属性元素-->
<Label.TextColor>Red</Label.TextColor>
</Label>
</StackLayout>

这时候TextColor虽然是Xamarin.Forms属性,但在XAML代码中使用XML元素来表示。  

将属性TextColor以XML标签的形式单独设置为一个元素,称为属性元素(Property Elements)。

属性元素标签中不能出现任何其他内容,属性值的内容定义在属性元素开始和结束标记之间。  

属性元素是XAML特有的语法,对于XML解码器,Label.Textcolor只是一个普通的子元素,并没有特殊意义。

3.3 附加属性

附加属性是一种特殊类型的属性,在一个类中定义,然后附加到其他对象,在XAML中以类.属性名的方式使用,如:


<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- 位于1行1列 -->
<Label Text="Top Left" Grid.Row="0" Grid.Column="0" />
<!-- 位于1行2列 -->
<Label Text="Top Right" Grid.Row="0" Grid.Column="1" />
<!-- 位于2行1列 -->
<Label Text="Bottom Left" Grid.Row="1" Grid.Column="0" />
<!-- 位于2行2列 -->
<Label Text="Bottom Right" Grid.Row="1" Grid.Column="1" />
</Grid>
</StackLayout>

Grid元素拥有RowDefinitions和ColumnDefinitions属性,他们声明了Grid的行和列以形成网格,但Grid并没有单元格的概念,所以不能将Grid中的元素直接写在单元格中,而是通过另一种方式。

可以看到Grid中的子元素Label中都包含一个Grid.Row和Grid.Column属性,这两个属性是定义在Grid对象中的,但是附加到Label对象,称为附加属性(Attached Properties)。

Grid.Row和Grid.Column分别指定了对应的Label位于Grid的几行几列,以达到将Label放置到对应单元格的效果。

关于附加属性,后续可能会详讲它的定义和使用,此处只讲语法。

3.4 内容属性

先看一段基础XAML代码:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"/>
</StackLayout>
</ContentPage>

在XAML中一个元素标签之间只能放该元素的属性值,并不支持直接将一个对象写在元素标签里。

而上述代码看起来就是直接将StackLayout对象写在ContentPage元素下,这是怎么回事呢?

在Xamarin.Forms中定义的作为XAML元素的类,可以加一个ContentProperty特性,该特性可以标记一个属性为内容属性。在ContentPage元素标签按F12,就可以看到该特性:

该特性将ContentPage的Content属性标记为内容属性。在XAML文件中,为Content属性赋值时就不需要写属性元素标签,在ContentPage开始标签和结束标签之间的内容都假定被赋值给Content属性。

StackLayout,Grid,AbsoluteLayout,RelativeLayout等布局元素都派生自Layout<View>,查看Layout<T>元数据也可以看到内容属性:

此外Label元素也同样包含内容属性:

因此常常可以看到Label的另一种写法:直接将Text属性放在Label标签之间。

<Label>Welcome to Xamarin.Forms!</Label>

看完以上叙述,你可能还并不太理解什么叫内容属性,下面看看没有使用内容属性语法的代码:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<ContentPage.Content>
<StackLayout>
<StackLayout.Children>
<Label>
<Label.Text>Welcome to Xamarin.Forms!</Label.Text>
</Label>
</StackLayout.Children>
</StackLayout>
</ContentPage.Content>
</ContentPage>

这是最开始那段代码用完整的属性元素写法写出来的,两段代码是等效的,可以做对比,就能轻松明白什么叫内容属性(Content Properties)。

友情提示:看懂内容属性需要先掌握属性元素。

4.标记扩展

XAML标记扩展是XAML中的一个重要功能,它可以将属性值设置为从其他源间接引用的对象或值,对于使用共享对象和整个应用程序中的常量以及数据绑定特别重要。

标记扩展在XAML文件中表现为“{属性设置}”。

通常情况下,属性可以设置为显示的值,如字符串,数字,枚举等,但有时候需要引用其他地方定义的值,或者进行代码处理,这时候就会用到XAML标记扩展,如:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">
<ContentPage.Resources>
<x:String x:Key="introduce">
Xamarin is a cross-platform mobile development tool
</x:String>
</ContentPage.Resources>
<StackLayout>
<!-- 使用标记扩展来使用ContentPage.Resoures里定义的值 -->
<Label Text="{StaticResource introduce}"/>
<Button Text="{StaticResource introduce}"/>
</StackLayout>
</ContentPage>

上述代码中,{StaticResource introduce}就是使用了标记扩展StaticResource来使用其他地方定义的属性值。因为StaticResource实现了IMarkupExtension接口,所以被称为标记扩展。

常用的标记扩展还有x:Static、x:Reference、x:Type、x:Array、x:Null、OnPlatform、OnIdiom等,此外你还可以自定义标记扩展。

关于标记扩展后续会深入了解。

5.数据绑定

XAML中提供了快捷和便利的数据绑定方式:{Binding}标记扩展。

在C#中进行数据绑定,通常会先设置目标的BindingContext为源目标对象,再调用目标对象的SetBinding方法。

但在XAML中,你可以通过{x:Static}、{StaticResource}、{x:Reference}等标记扩展来指定目标对象的BindingContext,然后使用{Binding}标记扩展来进行数据绑定。如:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage">

<StackLayout>
<Label x:Name="lblSource" Text="我是源对象" />

<Label x:Name="lbl" Text="{Binding Text}"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=lblSource}"/>
</StackLayout>

</ContentPage>

第二个Label使用{x:Reference}标记扩展,指定了第一个Label对象为数据源对象,然后第二个Label就可以使用{Binding}标记扩展,来使用数据源对象的属性,作为自己的属性。

上述代码将导致两个Label的文本内容都是“我是源对象”。

关于数据绑定后续会深入了解。

欢迎添加个人微信号:Like若所思。

欢迎关注我的公众号,不仅为你推荐最新的博文,还有更多惊喜和资源在等着你!一起学习共同进步!

posted @ 2019-08-28 11:23  cool2feel  阅读(937)  评论(0编辑  收藏  举报