属性和绑定

在开发拥有图形界面 (GUI) 的应用时,最常见的任务之一就是保持界面和数据的同步。例如,假设您使用传统开发工具创建了一个用于浏览和修改客户记录的 Web 应用。如果没有应用制作工具,您就得设法通过以下方式保持应用界面和数据库记录的同步:

  1. 在请求数据库中的下一条记录时,更新所有显示数据的界面元素。

  2. 为所有界面元素添加更改监听器,以确保用户的更改可反映在客户记录中。

  3. 更新当前客户记录以接收新数据。

为此,您需要编写和维护大量样板文件,这对于程序员来说是一项繁琐工作,如果您没有编程经验,则更会成为一大障碍。

应用制作工具能让您免于编写所有这些样板文件。您只需使用绑定来指示客户记录中的属性和微件的属性必须保持同步即可。所有这些绑定都可以在一个简单易用的直观界面中完成。应用制作工具会为您完成所有剩下的工作。

除了在这个常见的使用场景下让界面元素与底层值保持同步外,应用制作工具的绑定功能远不止于此。您还可以使用该绑定功能让任意两个应用制作工具属性保持同步,例如当前登录用户的电子邮件地址与某个数据源查询参数。实际上,由于应用制作工具中几乎所有对象(包括模型、数据源、微件和脚本)都具有绑定功能,因此您可以在各种应用制作工具属性之间使用绑定。

属性

简而言之,属性是应用制作工具对象的具名值。您可以在应用制作工具中获取和设置属性的值。大多数应用制作工具对象都具有可从应用各个部分访问的属性。

您可以通过以下多种方式设置属性:

  • 通过应用制作工具界面 - 在设置微件名称时
  • 通过绑定 - 在一个属性发生更改以反映来自另一个属性的更新时
  • 通过脚本 - 您可以使用 JavaScript 设置属性

您可以访问以下各种属性:

  • 数据库记录中的字段
  • 当前登录用户的电子邮件地址
  • 微件特性,如位置、名称或值

实际上,您可以在应用制作工具中的所有位置发现属性,最常见的位置是属性编辑器:

以及绑定选择器:

对象

让我们通过探讨对象来更深入了解属性。对象是应用制作工具和“应用制作工具”应用的构成元素,在应用制作工具中,几乎所有构成元素都是对象。这些构成元素有哪些呢?它们包括构成界面的微件、表示数据的记录、为您读取和写入数据的数据源对象以及其他种种。甚至应用本身也是一个对象。

例如,“文本区域”微件就是一个具有多个属性(包括 name 和 label)的应用制作工具对象。数据记录则是一个具有您定义的属性的应用对象,例如具有 name 属性的客户记录。

类型

所有应用制作工具属性都具有数据类型,这意味着它们只接受特定类型的值,例如数字或字符串。多数属性具有的都是简单类型,例如字符串、数字或布尔值,但也有些属性具有复杂类型。例如,微件的 parent 属性也是一个微件,因此其类型为“微件”

路径

在绑定或脚本中引用属性时,应用制作工具会使用路径表示法来指代这些属性。例如,对于属性名为 NamePerson 数据模型对象,会使用 Person.Name 来指代属性。

未定义

路径和属性值可以是“undefined”。 未定义与 null 不同。 例如,尚未加载的记录关系属性就是一个未定义的属性。 如 datasource.item.Name 之类的路径,如果最后一个属性 (Name) 为未定义,或者其任何部分(例如 datasourceitem)为未定义或为 null,则该路径为未定义。 通常,应用制作工具会将未定义的值视为 null。 但是,如果将输入微件的值设置为“undefined”,则这些微件会自行停用。 例如,您可以使用以下脚本清除文本框的值并停用该文本框:

textBox.value = undefined;
    

示例场景

以下示例展示了两个复杂属性 PersonAddress。它们均属于特殊类型,您可以在创建的模型中予以定义。这些类型不属于应用制作工具的内置类型。

Person
属性名称类型
Name字符串
Age数字
Address地址
Address
属性名称类型
Street字符串
City字符串
Zip字符串

由于 Person 的 Address 属性为“地址”类型,因此您可以使用路径表示法(即 Person.Address.City)来指代人员的位置。

绑定

绑定是一种让两个属性保持同步的机制。作为使用应用制作工具的开发者,您会经常声明自己想绑定两个属性(例如某个文本输入值和某个记录的字段),而应用制作工具将自动使它们保持同步:即,当一个属性发生更改时,也会随之设置另一个属性。

应用制作工具中的所有属性都是可观测的,这意味着您可以监听对属性所做的更改。当两个属性绑定后,可通过绑定监听或观测每个属性的更改;当一个属性发生更改时,便会相应更新另一个属性。

在应用制作工具中,一个常见的绑定示例就是将某个文本输入的值与数据源某一项的属性绑定。此绑定可通过应用制作工具的属性编辑器完成,如果要写出该绑定,则会是这样:

@widget.text <-> @datasource.item.MyField
    

绑定值的类型转换器

属性具有类型和值。值本身也具有类型,该类型必须与其属性的值匹配。例如,微件的 Name 属性是字符串类型,因此名称的值也应为字符串,而不能视为整数。

如果您想要将两个属性绑定在一起,则它们必须具有相同的类型,或者它们的值必须可以从一种类型转换为另一种类型。这也称为“类型转换”

例如,如果您为微件的 Name 属性赋予的值为 "6",则值 "6" 会被视为字符串,而不是数字。您可以将此属性绑定到另一个类型为整数的属性,应用制作工具的内置类型转换器会尝试在这两个属性之间执行值类型转换。

应用制作工具提供了很多内置的类型转换,因此大多数绑定都能正常执行。这些转换器为双向转换,会尽可能将值从一种类型转换为另一种类型。

原类型目标类型条件
字符串数字仅当原类型可以解析为数字时。
字符串布尔值仅当原类型为“true”或“false”时(不区分大小写)。
字符串日期仅当原类型是 YYYY-MM-DD 格式的日期时。
数字布尔值零转换为 false,任何其他值转换为 true
数组<A>数组<B>只要 A 和 B 兼容。

转换器

有时,您会希望绑定两个属性,并在这些属性之间进行一些自定义的数据转换。例如,您想将某个记录中的字段与界面中的文本字段绑定,但希望能在将用户输入保存到数据库前对其执行删除空格的处理。或者,您想使用应用制作工具的非默认类型转换所用的其他日期模式,将日期转换为字符串。 转换器可让您对属性路径指定转换。每个转换器会接受输入值并生成输出值,且大多数转换器也可接受输出值并将其转换回输入值。 您可以将这些转换连在一起。例如,若要去除字符串路径的输入和输出中的空格,您可以将文本字段的 value 属性与数据源记录的 Name 字段绑定:

@value <-> @datasource.item.Name#trim()
    

或者,在将文本字段的 value 属性与数据库中的日期字段 timestamp 绑定时,您可以将自定义日期指定为字符串格式:

@value <--> @datasource.item.TimeStamp#formatDate('yyyy/MM/dd HH:mm:ss');
    

您可以将转换器连在一起:

@value <-> @datasource.item.Name#nullToEmpty()#trim()
    

您可以在此处找到所有内置转换器的列表。

此外,转换器也可以应用于数组元素而不是数组本身。例如,如果您想使用投影中的各项填充“下拉列表”微件的 name 属性,便可如此操作。其语法相同,但需使用两个井号,而不是一个。

@names <-> @datasources.items..TimeStamp##formatDate('yyyy/MM/dd HH:mm:ss')
    

绑定中的顶层属性

在绑定对象的属性(如微件名称)时,您可使用绑定选择器浏览可用属性。应用制作工具会根据您要绑定的来源对象自动调整可用属性。此功能简化了与某些常用属性的绑定。例如,如果要绑定“按钮”微件的值,则绑定选择器会自动默认选择该微件的 datasource.item 属性,该属性通常包含模型的字段。

但是,您可能不想将微件或其他对象绑定到绑定选择器自动提供的建议目标。在此情况下,事先了解在绑定应用中的对象时可以浏览的两类常规属性将很有帮助。

全局可用的属性

您可以绑定到应用的任何属性。这些属性通常可通过 app 对象进行访问。绑定时,app 对象的所有属性都会进行分类,并对绑定公开。如需查看所有属性的详细文档,请参阅应用对象 API 文档

微件可用的属性

微件除了可以绑定到 app 对象的所有属性外,还可以绑定到另外两个属性:

  • widget - 微件本身。
  • datasource - 微件的数据源,这是绑定到微件的最常用对象。该属性也可以作为 @widget.datasource 提供,但为方便起见,datasource 会显示在界面编辑器的绑定选择器中。

绑定表达式

有时将两个属性直接绑定在一起还不够。通过在应用制作工具界面的绑定编辑器中使用表达式,您可以将绑定功能与 JavaScript 结合使用,以转换您要绑定的值。一旦表达式中使用的其中一个属性发生更改,应用制作工具就会评估表达式。注意:这会让绑定成为单向绑定。

例如,假设您有一个名为 MyDeleteButton 的删除按钮,您想要创建一个绑定,使得当数据库中没有要删除的记录时便停用该按钮。但是,无法通过直接绑定属性来表达此概念。我们有 enabled 属性和 @datasource.item 属性,同时我们知道没有记录项时,项值为 null。因此,利用这些信息,我们可以进行以下绑定:

@widget.enabled <-> @datasource.item != null
    

而且,仅当存在记录时才会启用该按钮。

其他资源

如需详细了解如何创建绑定表达式,请参阅绑定表达式客户端脚本。如需了解微件和客户端对象可用的所有属性和方法,请参阅微件 API客户端 API