在应用程序中,XAML 主要用于定义页面的可视内容,并配合 C# 代码隐藏文件一起工作。
代码隐藏文件为标记提供代码支持。 这两个文件共同为包含子视图和属性初始化的新类定义做出贡献。 在 XAML 文件中,使用 XML 元素和属性引用类和属性,并建立标记和代码之间的链接。
若要开始编辑第一个 XAML 文件,Visual Studio或Visual Studio for Mac创建新的 Xamarin.Forms 解决方案。 (选择以下对应于你的 environment.)
在Windows中,Visual Studio 2019",在"开始"窗口中单击"创建新项目"以创建新项目:
在“创建新项目”窗口中,在“项目类型”下拉菜单中选择“移动”,选择“移动应用()”,然后单击“下一步”按钮:
在"配置新项目"窗口中,将Project名称设置为XamlSamples (或你喜欢的任何) ,然后单击"创建"按钮。
在" 新建跨平台应用 "对话框中,单击 "空白",然后单击" 确定" 按钮:
在解决方案中创建四个项目:XamlSamples .NET Standard 库、XamlSamples.Android、XamlSamples.iOS和通用 Windows 平台解决方案XamlSamples.UWP。
创建 XamlSamples 解决方案后,可能需要通过选择各种平台项目作为解决方案启动项目,在手机仿真器或真实设备上生成和部署项目模板创建的简单应用程序,来测试开发环境。
除非需要编写特定于平台的代码,否则共享 XamlSamples .NET Standard库项目几乎可以花费所有编程时间。 这些文章不会超出该项目。
在 XamlSamples .NET Standard库中是一对具有以下名称的文件:
App.xaml,XAML文件;和
App.xaml.cs,一个与 XAML 文件关联的 C# 代码隐藏文件。
需要单击 App.xaml 旁边的箭头,以查看代码隐藏文件。
App.xaml和App.xaml.cs都参与名为 的类, 该类派生自 。 具有 XAML 文件的其他大多数类都参与派生自 的类;这些文件使用 XAML 定义整个页面 ContentPage
的可视内容。 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 命名空间 () URI,第一个似乎位于 Xamarin 网站上,第二个在 xmlns
Microsoft 网站上。 不要费心检查这些 URI 指向什么。 没有任何。 它们只是 Xamarin 和 Microsoft 拥有的 URI,基本上用作版本标识符。
第一个 XML 命名空间声明意味着 XAML 文件中定义的没有前缀的标记引用 中的类 Xamarin.Forms ,例如 ContentPage
。 第二个命名空间声明定义 的前缀 x
。 这用于 XAML 本身固有的多个元素和属性,这些元素和属性受 XAML 的其他实现支持。 但是,这些元素和属性略有不同,具体取决于 URI 中嵌入的年份。 Xamarin.Forms 支持 2009 XAML 规范,但并非全部支持。
命名空间 local
声明允许从库项目访问.NET Standard类。
第一个标记的末尾, x
前缀用于名为 的属性 Class
。 由于此前缀对 XAML 命名空间的使用几乎通用,因此 XAML 属性(如 )几乎 x
Class
始终称为 x:Class
。
特性 x:Class
指定完全限定的 .NET 类名: MainPage
命名空间中的 XamlSamples
类。 这意味着,此 XAML 文件在派生自 的命名空间中定义一个名为 的新类,该命名空间是 MainPage
XamlSamples
ContentPage
属性出现在的 x:Class
标记。
x:Class
属性只能出现在 XAML 文件的根元素中,以定义派生的 C# 类。 这是 XAML 文件中定义的唯一新类。 XAML 文件中显示的所有其他内容只是从现有类实例化并初始化。
MainPage.xaml.cs文件如下所示, (未使用的指令 ) :
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
类定义,其中包含从 InitializeComponent
构造函数调用的方法 MainPage
的定义。 然后, MainPage
可以一起编译这两个分部类定义。 根据是否编译 XAML,XAML 文件或 XAML 文件的二进制形式将嵌入到可执行文件中。
在运行时,特定平台项目中的代码调用 方法,将类的新实例传递到 .NET Standard LoadApplication
App
库中。 类 App
构造函数实例化 MainPage
。 该类的构造函数调用 ,然后调用方法,该方法从 (库中提取 XAML 文件) 编译) InitializeComponent
LoadFromXaml
二.NET Standard代码。 LoadFromXaml
初始化 XAML 文件中定义的所有对象,在父子关系中将它们全部连接在一起,将代码中定义的事件处理程序附加到 XAML 文件中设置的事件,并设置生成的对象树作为页面的内容。
虽然通常无需花费大量时间处理生成的代码文件,但有时在生成的文件中代码上引发运行时异常,因此应熟悉它们。
编译并运行此程序时,元素将显示在页面中心 Label
,如 XAML 建议:
若要将其他基于 XAML 的类添加到项目,请选择 ContentPage
ContentPage
库项目,右键单击并选择"添加新 项..."。在"添加新项"对话框中,选择"Visual C# 项 >内容页 (而不是内容页>这将创建一个仅代码页,或选择"内容视图",该页不是) 。 为页面命名,例如 HelloXamlPage:
向项目添加了两个文件:HelloXamlPage.xaml和代码隐藏文件HelloXamlPage.xaml.cs。
编辑 HelloXamlPage.xaml 文件,以便唯一的标记是 和 ContentPage.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
标记称为 "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 类 (如 ContentPage
或 Label
) 作为 XML 元素出现在 XAML 文件中。 该类的属性(包括的 Title
ContentPage
属性 Label
)通常显示为 XML 特性。
有很多快捷方式可用于设置这些属性的值。 某些属性是基本数据类型:例如, Title
和 Text
属性的类型为,类型 String
Rotation
为 Double
, IsVisible
true
默认情况下,默认情况下在此处设置 (为,) 的类型为 Boolean
。
HorizontalTextAlignment
属性的类型为 TextAlignment
,它是一个枚举。 对于任何枚举类型的属性,只需提供一个成员名称。
但对于更复杂类型的属性,转换器用于分析 XAML。 这些是 Xamarin.Forms 派生自的类 TypeConverter
。 很多是公共类,但某些不是公共类。 对于此特定的 XAML 文件,其中几个类在幕后扮演角色:
LayoutOptionsConverter
对于 VerticalOptions
属性
FontSizeConverter
对于 FontSize
属性
ColorTypeConverter
对于 TextColor
属性
这些转换器控制属性设置允许的语法。
ThicknessTypeConverter
可以处理用逗号分隔的一个、两个或四个数字。 如果提供一个数字,则应用于所有四个边。 如果有两个数字,则第一个是左对齐和右填充,第二个数字为顶部和底部。 四个数字按左、上、右和下顺序排列。
LayoutOptionsConverter
可以将结构的公共静态字段的名称转换 LayoutOptions
为类型的值 LayoutOptions
。
FontSizeConverter
可以处理 NamedSize
成员或数字字体大小。
ColorTypeConverter
接受结构或十六进制 RGB 值的公共静态字段的名称 Color
,带或不带 alpha 通道(前面带有数字符号) ( # ) 。 下面是没有 alpha 通道的语法:
TextColor="#rrggbb"
其中的每个小字母都是一个十六进制数字。 下面介绍如何包括 alpha 通道:
TextColor="#aarrggbb">
对于 alpha 通道,请记住,FF 是完全不透明的,00是完全透明的。
另外两种格式允许您为每个通道仅指定一个十六进制数字:
TextColor="#rgb"
TextColor="#argb"
在这些情况下,将重复该数字以形成值。 例如,#CF3 是 RGB 颜色 "CC-FF-33"。
运行 XamlSamples 程序时, 会显示。 若要查看新的, HelloXamlPage
可以将其设置为 HelloXamlPage
文件中的新启动页,或从导航到新页 MainPage
。
若要实现导航,请先更改 app.config 构造函数中的代码,以便 创建对象:
public App() { InitializeComponent(); MainPage = new NavigationPage(new MainPage()); }
在 MainPage 构造函数中,可以创建一个简单的 ,并使用事件处理程序导航到 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
页的属性将替换 Content
XAML 文件中属性的设置。 在编译和部署该程序的新版本时,屏幕上会出现一个按钮。 按下它将导航到 HelloXamlPage
。 下面是 iPhone、Android 和 UWP 上的结果页:
您可以使用 MainPage
iOS 上的 " MainPage
" 按钮导航回来,使用页面顶部的左箭头或 Android 上电话的底部,或者使用页面顶部的左箭头 Windows 10。
请随意对 XAML 进行试验,以提供不同的呈现方式 Label
。 如果需要将任何 Unicode 字符嵌入到文本中,则可以使用标准 XML 语法。 例如,若要将问候语置于智能引号中,请使用:
<Label Text="“Hello, XAML!”" … />
如下所示:
HelloXamlPage示例只包含 页上的一个,但这种情况非常罕见。 大多数 ContentPage
派生类型将 Content
属性设置为某种形式的布局,例如 StackLayout
。 Children
的属性 StackLayout
定义为类型 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
程序内执行一些操作。
如 数据绑定基础知识 使用来显示值的工作 Label
可以完全在 XAML 中使用数据绑定来处理。 但首先查看代码解决方案非常有用。 尽管如此,处理 Button
单击无疑也需要代码。 这意味着中的代码隐藏文件 XamlPlusCodePage
必须包含的事件的处理程序 ValueChanged
Slider
,以及的事件的处理程序 Clicked
Button
。 我们来添加它们:
namespace XamlSamples { public partial class XamlPlusCodePage { public XamlPlusCodePage() { InitializeComponent(); } void OnSliderValueChanged(object sender, ValueChangedEventArgs args) { } void OnButtonClicked(object sender, EventArgs args) { } } }
这些事件处理程序不需要是公共的。
返回到 XAML 文件, Slider
和 Button
标记需要包括 ValueChanged
Clicked
引用这些处理程序的和事件的特性:
<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>
请注意,为事件分配处理程序的语法与为属性赋值的语法相同。
如果的事件的处理程序 ValueChanged
Slider
将使用 Label
显示当前值,则该处理程序需要从代码中引用该对象。 Label
需要一个使用特性指定的名称 x:Name
。
<Label x:Name="valueLabel" Text="A simple Label" Font="Large" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
x
属性的前缀 x: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
。 让我们 Clicked
通过使用按钮的显示警报来模拟对事件的响应 Text
。 事件处理程序可以安全地将 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
运算符开头,后者将在方法完成时返回。 由于此方法 Button
从参数中获取触发事件 sender
,因此同一处理程序可用于多个按钮。
你已看到,在 XAML 中定义的对象可能会激发在代码隐藏文件中进行处理的事件,并且代码隐藏文件可以使用属性指定的名称访问在 XAML 中定义的对象 x:Name
。 这是代码和 XAML 交互的两种基本方法。
若要深入了解 XAML 的工作原理,可以通过检查新生成的 XamlPlusCode 文件搜集,该文件现在包含分配给任何 属性作为私有字段的任何名称。 下面是该文件的简化版本:
public partial class XamlPlusCodePage : ContentPage { private Label valueLabel; private void InitializeComponent() { this.LoadFromXaml(typeof(XamlPlusCodePage)); valueLabel = this.FindByName<Label>("valueLabel"); } }
此字段的声明允许在 XamlPlusCodePage
区域下的分部类文件中的任意位置自由使用该变量。 在运行时,将在分析 XAML 后分配该字段。 这意味着, valueLabel
null
当 XamlPlusCodePage
构造函数在调用后开始但有效时,该字段是 InitializeComponent
。
在将 InitializeComponent
控制权返回给构造函数后,该页面的视觉对象的构造方式与在代码中实例化和初始化相同。 XAML 文件不再扮演类中的任何角色。 您可以使用任何所需的方式在页面上操作这些对象,例如,通过将视图添加到 StackLayout
,或将页面的 Content
属性设置为其他内容。 您可以通过检查 Content
页的属性和布局集合中的项来 "遍历树" Children
。 您可以为以这种方式访问的视图设置属性,或以动态方式向它们分配事件处理程序。
欢迎。 这是您的页面,而 XAML 只是生成其内容的工具。
本文介绍了 XAML 文件和代码文件如何影响类定义以及 XAML 和代码文件如何交互。 但 XAML 还具有自己独特的语法功能,使其能够以非常灵活的方式使用。 你可以在第2部分中开始浏览这些项 。基本 XAML 语法。