Xamarin.Forms 快速入门深入探讨

Xamarin.Forms 快速入门中,生成了 Notes 应用程序。 本文对已生成的内容进行回顾,以深入了解有关 Xamarin.Forms Shell 应用程序工作原理的基础知识。

Visual Studio 简介

Visual Studio 将代码组织为解决方案和项目。 解决方案是可以容纳一个或多个项目的容器。 项目可以是应用程序、支持库、测试应用程序等。 Notes 应用程序包含 1 个内附 3 个项目的解决方案,如以下屏幕截图所示:

Visual Studio解决方案资源管理器

这些项目如下:

  • Notes - 此项目是 .NET Standard 库项目,其中包含所有共享代码和共享 UI。
  • Notes.Android - 此项目包含 Android 特定代码,是 Android 应用程序的入口点。
  • Notes.iOS - 此项目包含 iOS 特定代码,是 iOS 应用程序的入口点。

Xamarin.Forms 应用程序的剖析

以下屏幕截图显示 Visual Studio 中 Notes .NET Standard 库项目的内容:

Phoneword .NET Standard 项目内容

项目具有包含 NuGet 和 SDK 节点的依赖项节点 :

  • NuGet - 已添加到项目的 Xamarin.Forms、Xamarin.Essentials、Newtonsoft.Json 和 sqlite-net-pcl NuGet 包。
  • SDK - NETStandard.Library 元包,它引用定义 .NET Standard 的一整套 NuGet 包。

Visual Studio for Mac 简介

Visual Studio for Mac 遵循将代码组织为解决方案和项目的 Visual Studio 做法 。 解决方案是可以容纳一个或多个项目的容器。 项目可以是应用程序、支持库、测试应用程序等。 Notes 应用程序包含 1 个内附 3 个项目的解决方案,如以下屏幕截图所示:

Visual Studio for Mac 解决方案窗格

这些项目如下:

  • Notes - 此项目是 .NET Standard 库项目,其中包含所有共享代码和共享 UI。
  • Notes.Droid - 此项目包含 Android 特定代码,是 Android 应用程序的入口点。
  • Notes.iOS - 此项目包含 iOS 特定代码,是 iOS 应用程序的入口点。

Xamarin.Forms 应用程序的剖析

以下屏幕截图显示 Visual Studio for Mac 中 Notes .NET Standard 库项目的内容:

Phoneword .NET Standard 库项目内容

项目具有包含 NuGet 和 SDK 节点的依赖项节点 :

  • NuGet - 已添加到项目的 Xamarin.Forms、Xamarin.Essentials、Newtonsoft.Json 和 sqlite-net-pcl NuGet 包。
  • SDK - NETStandard.Library 元包,它引用定义 .NET Standard 的一整套 NuGet 包。

该项目还包括多个文件:

  • Data\NoteDatabase.cs – 此类包含用于创建数据库、从中读取数据、向其写入数据以及从中删除数据的代码。
  • Models\Note.cs – 此类定义一个 Note 模型,其实例在应用程序中存储有关每个便笺的数据。
  • Views\AboutPage.xaml - AboutPage 类的 XAML 标记,该类定义“关于”页面的 UI。
  • Views\AboutPage.xaml.cs - AboutPage 类的代码隐藏,该类包含用户与页面交互时执行的业务逻辑。
  • Views\NotesPage.xaml - NotesPage 类的 XAML 标记,该类定义应用程序启动时所显示页的 UI。
  • Views\NotesPage.xaml.cs - NotesPage 类的代码隐藏,该类包含用户与页面交互时执行的业务逻辑。
  • Views\NoteEntryPage.xaml - NoteEntryPage 类的 XAML 标记,该类定义用户输入便笺时所显示页的 UI。
  • Views\NoteEntryPage.xaml.cs - NoteEntryPage 类的代码隐藏,该类包含用户与页面交互时执行的业务逻辑。
  • App.xaml - App 类的 XAML 标记,该类定义应用程序的资源字典。
  • App.xaml.cs - App 类的代码隐藏,该类负责实例化 Shell 应用程序,并处理应用程序生命周期事件。
  • AppShell.xaml - AppShell 类的 XAML 标记,该类用于定义应用程序的视觉层次结构。
  • AppShell.xaml.cs - AppShell 类的代码隐藏,该类为 NoteEntryPage 创建一个路由,以便能够以编程方式导航到该路由。
  • AssemblyInfo.cs –此文件包含在程序集级别应用的有关项目的应用程序属性。

有关 Xamarin.iOS 应用程序剖析的详细信息,请参阅 Xamarin.iOS 应用程序剖析。 有关 Xamarin.Android 应用程序剖析的详细信息,请参阅 Xamarin Android 应用程序剖析

体系结构和应用程序基础知识

Xamarin.Forms 应用程序采用与传统跨平台应用程序相同的构建方式。 共享代码通常位于 .NET Standard 库中,平台特定应用程序将使用此共享代码。 下图概要演示了 Notes 应用程序的这种关系:

Notes 体系结构

若要最大限度重用启动代码,Xamarin.Forms 应用程序需有一个名为 App 的单个类,该类负责实例化每个平台上的应用程序,如以下代码示例所示:

using Xamarin.Forms;

namespace Notes
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();
            MainPage = new AppShell();
        }
        // ...
    }
}

此代码将 App 类的 MainPage 属性设置为 AppShell 对象。 AppShell 类定义应用程序的视觉层次结构。 Shell 获取此视觉层次结构,并为其生成用户界面。 若要详细了解如何定义应用程序的视觉层次结构,请参阅应用程序视觉层次结构

此外,AssemblyInfo.cs 文件包含在程序集级别应用的单个应用程序属性:

using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

XamlCompilation 属性可打开 XAML 编译器,以使 XAML 直接编译为中间语言。 有关详细信息,请参阅 XAML 编译

在每个平台上启动应用程序

如何在每个平台上启动应用程序是根据平台而异的。

iOS

为了在 iOS 中启动初始 Xamarin.Forms 页面,Notes.iOS 项目定义了继承自 FormsApplicationDelegate 类的 AppDelegate 类:

namespace Notes.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
            return base.FinishedLaunching(app, options);
        }
    }
}

通过调用 Init 方法,FinishedLaunching 替代会初始化 Xamarin.Forms 框架。 这会导致在通过调用 LoadApplication 方法来设置根视图控制器之前,先将特定于 iOS 的 Xamarin.Forms 实现加载到应用程序。

Android

为了在 Android 中启动 Xamarin.Forms 初始页面,Notes.Android 项目包括使用 MainLauncher 属性创建 Activity 的代码,以及继承自 FormsAppCompatActivity 类的活动:

namespace Notes.Droid
{
    [Activity(Label = "Notes",
              Icon = "@mipmap/icon",
              Theme = "@style/MainTheme",
              MainLauncher = true,
              ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle savedInstanceState)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(savedInstanceState);
            global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
            LoadApplication(new App());
        }
    }
}

通过调用 Init 方法,OnCreate 替代会初始化 Xamarin.Forms 框架。 这会导致在加载 Xamarin.Forms 应用程序之前,将特定于 Android 的 Xamarin.Forms 实现加载到应用程序。

应用程序视觉层次结构

Xamarin.Forms Shell 应用程序定义一个类中的应用程序的视觉层次结构,该类是 Shell 类的子类。 在 Notes 应用程序中,这是 Appshell 类:

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
       xmlns:views="clr-namespace:Notes.Views"
       x:Class="Notes.AppShell">
    <TabBar>
        <ShellContent Title="Notes"
                      Icon="icon_feed.png"
                      ContentTemplate="{DataTemplate views:NotesPage}" />
        <ShellContent Title="About"
                      Icon="icon_about.png"
                      ContentTemplate="{DataTemplate views:AboutPage}" />
    </TabBar>
</Shell>

此 XAML 包含两个主要对象:

  • TabBarTabBar 表示底部选项卡栏,并且应在应用程序的导航模式使用底部选项卡时使用。 TabBar 对象是 Shell 对象的子对象。
  • ShellContent,它表示 TabBar 中每个选项卡的 ContentPage 对象。 每个 ShellContent 对象都是 TabBar 对象的一个子对象。

上述对象不表示任何用户界面,而表示应用程序视觉层次结构的组织。 Shell 使用这些对象,生成内容的导航用户界面。 因此,AppShell 类定义两个可从底部选项卡导航的页面。 页面按需创建,以响应导航。

有关 Shell 应用程序的详细信息,请参阅 Xamarin.Forms Shell

用户界面

可使用几个控件组创建 Xamarin.Forms 应用程序的用户界面:

  1. 页面 - Xamarin.Forms 页面呈现跨平台移动应用程序屏幕。 Notes 应用程序使用 ContentPage 类显示单个屏幕。 有关代码页的详细信息,请参阅 Xamarin.Forms 页面
  2. 视图 - Xamarin.Forms 视图是显示在用户界面上的控件,如标签、按钮和文本输入框。 已完成的 Notes 应用程序使用 CollectionViewEditorButton 视图。 有关视图的详细信息,请参阅 Xamarin.Forms 视图
  3. 布局 - Xamarin.Forms 布局是用于将视图组合到逻辑结构的容器。 Notes 应用程序使用 StackLayout 类采用垂直叠放来排列视图,并使用 Grid 类水平排列按钮。 有关布局的详细信息,请参阅 Xamarin.Forms 布局

在运行时,每个控件都会映射到其本身的本机等效项(即呈现的内容)。

布局

Notes 应用程序使用 StackLayout 在屏幕上自动排列视图而不考虑屏幕大小,从而简化了跨平台应用程序开发。 根据添加顺序,以垂直方式或水平方式逐个放置每个子元素。 StackLayout 使用的空间大小取决于 HorizontalOptionsVerticalOptions 属性的设置方式,但默认情况下,StackLayout 尝试使用整个屏幕。

以下 XAML 代码举例说明了如何使用 StackLayoutNoteEntryPage 进行布局:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    ...    
    <StackLayout Margin="{StaticResource PageMargin}">
        <Editor Placeholder="Enter your note"
                Text="{Binding Text}"
                HeightRequest="100" />
        <Grid>
            ...
        </Grid>
    </StackLayout>    
</ContentPage>

默认情况下,StackLayout 采用垂直方向。 但是,可以通过将 StackLayout.Orientation 属性设置为 StackOrientation.Horizontal 枚举成员来更改为水平方向。

注意

可以通过 HeightRequestWidthRequest 属性设置视图的大小。

有关 StackLayout 类的详细信息,请参阅 Xamarin.FormsStackLayout

响应用户交互

XAML 中定义的对象可触发在隐藏文件中处理的事件。 以下代码示例演示了 NoteEntryPage 类的代码隐藏中的 OnSaveButtonClicked 方法,执行该方法是为了响应在“保存”按钮上触发的 Clicked 事件。

async void OnSaveButtonClicked(object sender, EventArgs e)
{
    var note = (Note)BindingContext;
    note.Date = DateTime.UtcNow;
    if (!string.IsNullOrWhiteSpace(note.Text))
    {
        await App.Database.SaveNoteAsync(note);
    }
    await Shell.Current.GoToAsync("..");
}

OnSaveButtonClicked 方法将便笺保存在数据库中,并导航回上一页。 有关导航的详细信息,请参阅导航

注意

XAML 类的代码隐藏文件可使用为其分配的、具有 x:Name 属性的名称访问 XAML 中定义的对象。 分配给此属性的值与 C# 变量的规则相同,因为该值必须以字母或下划线开头,且不包含嵌入的空格。

NoteEntryPage 类的 XAML 标记中将保存按钮与 OnSaveButtonClicked 方法关联起来:

<Button Text="Save"
        Clicked="OnSaveButtonClicked" />

列表

CollectionView 负责在列表中显示项的集合。 默认情况下,列表项是垂直显示的,每个项以单行显示。

下面的代码示例演示来自 NotesPageCollectionView

<CollectionView x:Name="collectionView"
                Margin="{StaticResource PageMargin}"
                SelectionMode="Single"
                SelectionChanged="OnSelectionChanged">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical"
                           ItemSpacing="10" />
    </CollectionView.ItemsLayout>
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <StackLayout>
                <Label Text="{Binding Text}"
                       FontSize="Medium" />
                <Label Text="{Binding Date}"
                       TextColor="{StaticResource TertiaryColor}"
                       FontSize="Small" />
            </StackLayout>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

CollectionView 中每行的布局在 CollectionView.ItemTemplate 元素中定义,并使用数据绑定显示应用程序检索到的任何便笺。 CollectionView.ItemsSource 属性在 NotesPage.xaml.cs 中设置为数据源:

protected override async void OnAppearing()
{
    base.OnAppearing();

    collectionView.ItemsSource = await App.Database.GetNotesAsync();
}

此代码将 CollectionView 用数据库中存储的任何便笺填充,并在页面出现时执行。

CollectionView 中选择了一项时,会触发 SelectionChanged 事件。 当事件触发时,会执行名为 OnSelectionChanged 的事件处理程序:

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // ...
    }
}

SelectionChanged 事件可以通过 e.CurrentSelection 属性访问与项关联的对象。

有关 CollectionView 类的详细信息,请参阅 Xamarin.Forms CollectionView

通过指定要导航到的 URI,可以在 Shell 应用程序中执行导航。 导航 URI 有三个组件:

  • 一个路由,它定义了作为 Shell 视觉层次结构的一部分存在的内容的路径。
  • 一个页。 Shell 视觉层次结构中不存在的页可以从 Shell 应用程序中的任何位置推送到导航堆栈。 例如,不会在 Shell 视觉层次结构中定义 NoteEntryPage,但可以根据需要将其推送到导航堆栈。
  • 一个或多个查询参数。 查询参数是可以在导航时传递到目标页的参数。

导航 URI 不必包含全部三个组件,但当它包含全部三个组件时,结构为://route/page?queryParameters

注意

可以通过 Route 属性在 Shell 视觉层次结构中的元素上定义路由。 但是,如果未设置 Route 属性(如在 Notes 应用程序中),则会在运行时生成路由。

有关 Shell 导航的详细信息,请参阅 Xamarin.Forms Shell 导航

注册路由

若要导航到 Shell 视觉层次结构中不存在的页,需要先在 Shell 路由系统中注册它。 具体使用的是 Routing.RegisterRoute 方法。 在 Notes 应用程序中,这种情况发生在 AppShell 构造函数中:

public partial class AppShell : Shell
{
    public AppShell()
    {
        // ...
        Routing.RegisterRoute(nameof(NoteEntryPage), typeof(NoteEntryPage));
    }
}

在本例中,为 NoteEntryPage 类型注册了一个名为 NoteEntryPage 的路由。 然后可以使用基于 URI 的导航从应用程序中的任何位置导航到此页面。

执行导航

导航由 GoToAsync 方法执行,该方法接受表示要导航到的路由的参数:

await Shell.Current.GoToAsync("NoteEntryPage");

在本例中,NoteEntryPage 是要导航到的位置。

重要

当导航到不在 Shell 视觉层次结构中的页面时,将创建一个导航堆栈。

导航到一个页面时,可以将数据作为查询参数传递到该页面:

async void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.CurrentSelection != null)
    {
        // Navigate to the NoteEntryPage, passing the ID as a query parameter.
        Note note = (Note)e.CurrentSelection.FirstOrDefault();
        await Shell.Current.GoToAsync($"{nameof(NoteEntryPage)}?{nameof(NoteEntryPage.ItemId)}={note.ID.ToString()}");
    }
}

本示例检索 CollectionView 中当前选定的项,并导航到 NoteEntryPage,同时将 Note 对象的 ID 属性的值作为查询参数传递到 NoteEntryPage.ItemId 属性。

为了接收传递的数据,NoteEntryPage 类用 QueryPropertyAttribute 进行修饰

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }
    }
    // ...
}

QueryPropertyAttribute 的第一个参数指定将接收传递的数据的 ItemId 属性,第二个参数指定查询参数 ID。因此,上述示例中的 QueryPropertyAttribute 指定 ItemId 属性将接收从 GoToAsync 方法调用中的 URI 传入 ItemId 查询参数的数据。 然后,ItemId 属性调用 LoadNote 方法以从设备检索便笺。

向后导航通过将“..”指定为 GoToAsync 方法的参数来执行:

await Shell.Current.GoToAsync("..");

有关向后导航的详细信息,请参阅向后导航

数据绑定

数据绑定用于简化 Xamarin.Forms 应用程序显示及其与数据的交互方式。 它将在用户界面和基础应用程序之间建立连接。 BindableObject 类包含大部分基础结构以支持数据绑定。

数据绑定连接两个对象,即源和目标。 源对象提供数据。 目标对象使用(并经常显示)来自源对象的数据。 例如,Editor(target 对象)通常会将其 Text 属性绑定到 source 对象中的公共 string 属性。 下图说明了这种绑定关系:

数据绑定

数据绑定的主要优点是让你无需再担心视图和数据源之间的数据同步。 幕后的绑定框架源会将源对象中的更改自动推送到目标对象,且目标对象中的更改可选择性地推送回源对象。

创建数据绑定只需两个步骤:

  • target 对象的 BindingContext 属性必须设置为 source。
  • 必须在目标和源之间建立绑定。 在 XAML 中,此过程可通过使用 Binding 标记扩展实现。

在 Notes 应用程序中,绑定目标是显示便笺的 Editor,而设置为 的 NoteEntryPageBindingContextNote 实例是绑定源。 最初,在执行页面构造函数时,会设置 NoteEntryPageBindingContext

public NoteEntryPage()
{
    // ...
    BindingContext = new Note();
}

在本示例中,在创建 NoteEntryPage 时,将页面的 BindingContext 设置为新的 Note。 这会处理将新便笺添加到应用程序的场景。

此外,当导航到 NoteEntryPage 时,也可以设置页面的 BindingContext,前提是在 NotesPage 上选择了现有的便笺:

[QueryProperty(nameof(ItemId), nameof(ItemId))]
public partial class NoteEntryPage : ContentPage
{
    public string ItemId
    {
        set
        {
            LoadNote(value);
        }

        async void LoadNote(string itemId)
        {
            try
            {
                int id = Convert.ToInt32(itemId);
                // Retrieve the note and set it as the BindingContext of the page.
                Note note = await App.Database.GetNoteAsync(id);
                BindingContext = note;
            }
            catch (Exception)
            {
                Console.WriteLine("Failed to load note.");
            }
        }    
        // ...    
    }
}

在本示例中,当页面导航发生时,从数据库中检索到页面的 BindingContext 后,它会被设置为选定的 Note 对象。

重要

虽然可以分别设置每个 target 对象的 BindingContext 属性,但没有必要。 BindingContext 是特殊属性,其所有子级都会继承该属性。 因此,当 ContentPage 上的 BindingContext 设置为 Note 实例时,ContentPage 的所有子级都具有相同的 BindingContext,并且都可绑定到 Note 对象的公共属性。

NoteEntryPage 中的 Editor 随后会绑定到 Note 对象的 Text 属性:

<Editor Placeholder="Enter your note"
        Text="{Binding Text}" />

Editor.Text 属性和 source 对象的 Text 属性之间建立绑定。 Editor 中所做的更改将自动传播到 Note 对象。 同样,如果更改了 Note.Text 属性,Xamarin.Forms 绑定引擎也会更新 Editor 的内容。 这称为双向绑定。

若要深入了解数据绑定,请参阅 Xamarin.Forms 数据绑定

“样式”

Xamarin.Forms 应用程序通常包含多个具有相同外观的视觉对象元素。 设置每个视觉对象元素的外观可能是重复性的并且容易出错。 相反,可以创建用于定义外观的样式,然后将其应用于所需的视觉对象元素。

Style 类将属性值的集合分组到一个对象中,然后可以将该对象应用于多个视觉对象元素实例。 样式以应用程序级别、页面级别或视图级别存储在 ResourceDictionary 中。 选择在何处定义 Style 会影响其应用范围:

  • 在应用程序级别定义的 Style 实例可以应用于整个应用程序。
  • 在页面级别定义的 Style 实例可以应用于页面及其子级。
  • 在视图级别定义的 Style 实例可以应用于视图及其子级。

重要

在整个应用程序中使用的任何样式都存储在应用程序的资源字典中以避免重复。 但是,特定于页面的 XAML 不应包含在应用程序的资源字典中,因为这些资源随后会在应用程序启动时(而不是页面需要时)进行分析。 有关详细信息,请参阅减小应用程序资源字典大小

每个 Style 实例都包含一个或多个 Setter 对象的集合,其中每个 Setter 都具有 PropertyValueProperty 是应用样式的元素的可绑定属性的名称,而 Value 是应用于属性的值。 下面的代码示例演示来自 NoteEntryPage 的样式:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Notes.Views.NoteEntryPage"
             Title="Note Entry">
    <ContentPage.Resources>
        <!-- Implicit styles -->
        <Style TargetType="{x:Type Editor}">
            <Setter Property="BackgroundColor"
                    Value="{StaticResource AppBackgroundColor}" />
        </Style>
        ...
    </ContentPage.Resources>
    ...
</ContentPage>

此样式应用于页面上的任何 Editor 实例。

创建 Style 时,始终需要 TargetType 属性。

注意

在传统上,使用 XAML 样式对 Xamarin.Forms 应用程序设置样式。 但是,Xamarin.Forms 还支持使用级联样式表 (CSS) 对视觉对象元素设置样式。 有关详细信息,请参阅使用级联样式表 (CSS) 设置 Xamarin.Forms 应用的样式

有关 XAML 样式的详细信息,请参阅使用 XAML 样式设置 Xamarin.Forms 应用的样式

测试和部署

Visual Studio for Mac 和 Visual Studio 均提供许多用于测试和部署应用程序的选项。 调试应用程序是应用程序开发生命周期的普遍一环,有助于诊断代码问题。 有关详细信息,请参阅设置断点逐步执行代码日志窗口的输出信息

模拟器是开始部署和测试应用程序的有利位置,其提供用于测试应用程序的有用功能。 但是,用户不会在模拟器中使用最终应用程序,因此应尽早并经常在实际设备上测试应用程序。 有关 iOS 设备预配的详细信息,请参阅设备预配。 有关 Android 设备预配的详细信息,请参阅设置设备进行开发

后续步骤

本深入探讨介绍了使用 Xamarin.Forms Shell 开发应用程序的基础知识。 建议的后续步骤包括了解以下功能:

  • Xamarin.Forms Shell 可通过提供大多数应用程序所需的基本功能简化移动应用程序开发的复杂性。 有关详细信息,请参阅 Xamarin.Forms Shell
  • 可使用几个控件组创建 Xamarin.Forms 应用程序的用户界面。 有关详细信息,请参阅控件引用
  • 数据绑定将两个对象的属性链接起来,对某一属性的更改就会自动反映在另一个属性中。 有关详细信息,请参阅数据绑定
  • Xamarin.Forms 提供多种页面导航体验,具体取决于所使用的页面类型。 有关详细信息,请参阅导航
  • 样式有助于减少重复的标记,并且使用样式可以更轻松地更改应用程序的外观。 有关详细信息,请参阅设置 Xamarin.Forms 应用的样式
  • 数据模板让你可以在支持的视图上定义数据表示形式。 有关详细信息,请参阅数据模板
  • 还可以自定义每个平台上的本机控件的效果。 通过子类化 PlatformEffect 类在特定于平台的项目中创建效果,并将其附加到相应的 Xamarin.Forms 控件中使用。 有关详细信息,请参阅效果
  • 通过 Renderer 类可以在每个平台上以不同方式呈现每个页面、布局和视图,反过来又可以创建本机控件,在屏幕上排列该控件,并添加共享代码中指定的行为。 开发人员可以实现自定义 Renderer 类,以自定义控件的外观和/或行为。 有关详细信息,请参阅自定义呈现器
  • 共享代码可通过 DependencyService 类访问本机功能。 有关详细信息,请参阅通过 DependencyService 访问本机功能

第 9 频道YouTube 上查找更多 Xamarin 视频。