Xamarin.iOS 中的 .xib 代码生成

Apple Interface Builder 工具 (“IB”) 可用于直观地设计用户界面。 IB 创建的接口定义保存在 .xib 文件中。 可以为 .xib 文件中的小组件和其他对象提供“类标识”,该标识可以是自定义用户定义类型。 使用自定义类型可以自定义小组件的行为并编写自定义小组件。

这些用户类通常是 UI 控制器类的子类。 它们具有 连接到接口对象的 (属性) 和 操作 (事件) 。 在运行时,将加载 IB。 此时,将创建对象,并将出口和操作动态连接到各种 UI 对象。 定义这些托管类时,必须定义所有操作和出口,以匹配 IB 期望的操作和出口。 Visual Studio for Mac使用类似于 CodeBehind 的模型来简化代码。 Xcode 具有类似的 Objective-C 模型。 但 Xamarin.iOS 代码生成模型和约定已经过调整,使 .NET 开发人员更熟悉。

.xib 文件和自定义类

除了使用 Cocoa Touch 中的现有类型外,还可以在 .xib 文件中定义自定义类型。 还可以使用在其他 .xib 文件中定义或纯在 C# 代码中定义的类型。 目前,Interface Builder 不知道在当前 .xib 文件外部定义的类型的详细信息,因此它不会列出它们或显示其自定义输出口和操作。 计划在未来某个时候删除此限制。

可以使用 Interface Builder 的“类”选项卡中的“添加子类”命令在 .xib 文件中定义自定义类。 我们将这些类称为“CodeBehind”类。 如果 .xib 文件在项目中具有对应的“.xib.designer.cs”文件,则Visual Studio for Mac将自动使用 .xib 中所有自定义类的分部类定义填充该文件。 我们将这些分部类称为“设计器类”。

生成代码

对于具有 Page 生成操作的任何{0} .xib 文件,可通过存在 .xib.designer.cs 文件来启用代码生成。{0} Visual Studio for Mac在设计器文件中为可以在 .xib 文件中找到的所有用户类生成分部类。 Visual Studio for Mac为操作生成输出口的属性和分部方法。

.xib 文件更改并Visual Studio for Mac重新获得焦点时,设计器文件会自动更新。 不建议对设计器文件进行更改,因为下次Visual Studio for Mac更新文件时将覆盖更改。

注册和命名空间

Visual Studio for Mac使用设计器文件位置的项目默认命名空间生成设计器类。 此行为与正常的 .NET 项目命名空间生成一致。 设计器文件的命名空间使用项目的“默认命名空间”及其“.NET 命名策略”设置。 如果项目的默认命名空间发生更改,重新生成的类将使用新的命名空间。 重新生成后,你可能会发现分部类不再匹配。

若要使类可由Objective-C运行时发现,Visual Studio for Mac向类应用[Register (name)]属性。 尽管 Xamarin.iOS 会自动注册 NSObject派生类,但它使用完全限定的 .NET 名称。 Visual Studio for Mac 应用的属性会替代 Xamarin.iOS 行为,以确保使用 .xib 文件中使用的名称注册每个类。 为使用 IB 定义的所有自定义类手动添加 属性,而无需使用 Visual Studio for Mac 生成设计器文件。 这样做会使托管类与预期的 Objective-C 类名称匹配。

类不能在多个 .xib 中定义,否则它们将发生冲突。

非Designer类部件

Designer分部类不应按原样使用。 插座是专用的,未指定基类。 预期每个类在另一个文件中都有相应的“非设计器”类部件。 “非设计器”文件设置基类,操作输出口,并定义从本机代码实例化类所需的构造函数。 默认 的 .xib 模板具有“非设计器”类部件,但对于在 .xib 中定义的任何其他自定义类,必须手动添加非设计器部件。

为了获得灵活性,需要使用分部类进行这种分离。 例如,多个 CodeBehind 类可以子类一个公共托管抽象类,该类子类由 IB 子类化。

通常,将 CodeBehind 类放在 {0}.xib.designer.cs 设计器文件旁边的 {0}.xib.cs 文件中。

生成的操作和输出口

在分部设计器类中,Visual Studio for Mac生成与 IB 中定义的任何连接出口对应的属性,以及对应于任何连接操作的分部方法。

出口属性

Designer类包含与自定义类上定义的所有输出口对应的属性。 这些属性支持延迟绑定。 它们是 Xamarin.iOS 到 Objective C 桥的实现细节。 将它们视为等效于专用字段,旨在仅在 CodeBehind 类中使用。 通过将公共访问器添加到非设计器类部件中的 字段,使字段公开。

如果出口属性定义为具有与) 等效NSObjectid (类型,则设计器代码生成器当前根据连接到该输出口的对象确定最强的类型,以便方便起见。 但是,将来的版本可能不支持此行为。 建议在定义自定义类时显式强键入输出口。

操作属性

Designer类包含与自定义类上定义的所有操作对应的分部方法。 这些方法没有实现。 分部方法的用途有两个:

  1. 如果在非设计器类部件的类主体中键入partial,Visual Studio for Mac将提供自动完成所有未实现的分部方法的签名。
  2. 分部方法签名应用了一个向世界公开它们的 Objective-C 属性,因此它们可以作为相应的操作进行处理。

可以忽略分部方法,并通过将 属性应用于其他方法来实现 操作。 或者让它落到基类。

如果将操作定义为发送方类型 id (等效于 NSObject) ,则设计器代码生成器当前根据连接到该操作的对象确定最强的类型。 但是,将来的版本可能不支持此行为。 建议在定义自定义类时显式强键入操作。

这些分部方法仅为 C# 创建,因为 CodeDOM 不支持分部方法。 它们不是针对其他语言生成的。

跨 XIB 类用法

有时,用户希望从多个 .xib 文件中引用同一类,例如使用选项卡控制器。 可以从另一个 .xib 文件显式引用类定义,或者在第二个 .xib 中再次定义相同的类名。

后一种情况可能会有问题,因为Visual Studio for Mac单独处理 .xib 文件。 Visual Studio for Mac无法检测和合并重复定义。 在多个设计器文件中定义同一分部类时,最终可能会出现多次应用 Register 属性的冲突。 最新版本的 Visual Studio for Mac尝试解决冲突,但可能无法始终按预期工作。 将来,此行为可能会变得不受支持,Visual Studio for Mac将使项目中所有 .xib 文件和托管代码中定义的所有类型都从所有 .xib 文件中直接可见。

类型解析

IB 中使用的类型是 Objective-C 使用 Register 属性映射到 CLR 类型的类型名称。 生成代码时,Visual Studio for Mac将解析 CLR 类型,并将类型名称完全限定为Objective-C类型。 这些 Objective-C 类型由 Xamarin.iOS 核心包装。

代码生成器当前无法从 Objective-C 用户代码或库中的类型名称解析 CLR 类型。 在这种情况下,它会逐字输出类型名称。 它必须具有与类型相同的名称 Objective-C 才能正确解析 CLR 类型。 CLR 类型必须与使用它的代码位于同一命名空间中。 代码生成器的未来版本将考虑项目中的所有 Objective-C 类型。