Vaadin:如何绑定实体 "meta data"

Vaadin: How to bind entity "meta data"

我正在尝试弄清楚如何绑定关于实体的元数据,而该实体不是实体中的实际字段。例如,考虑以下内容:

Task:
    title: string
    description: string
    ...
    notes: List<TaskNote>

我希望能够在网格或“编辑器”表单中显示 Task 并显示,比如与 [=12] 关联的 TaskNote 的计数=].因此,在这种情况下,计数只是 notes 列表中的项目数。

如何为这样的东西创建数据绑定?什么是最好的practices/techniques?

Binder 用于将 Fields 绑定到特定 bean 的 PropertiesPerson bean 可以有 Properties“名字”、“姓氏”和“出生年份”。但是,FieldProperty是比较抽象的概念,给大家留下了很大的回旋余地。

  • A Field 是实现 HasValue 接口的东西,通常是 ComponentHasValue 接口(因此 Field)有一个 Java 类型,例如 String.
  • 一对Property本质上是一对getter/setter。该对必须具有匹配的类型 - getter 的 return 类型必须与 setter 作为输入的类型匹配。
    • Property 的 getter 可以通过实现 ValueProvider 函数接口来提供,在简单的形式中,可以是 Lambda 表达式,例如 person -> person.getFirstName()
    • setter 可以提供 Setter 功能接口的实现。作为 Lambda 的一个简单示例是 (person, newFirstName) -> person.setFirstName(newFirstName).

创建 Binder 时,您以某种方式提供了 ValueProviderSetter;最明确的方式是当你像这样绑定时:

Binder<Person> binder = new Binder<>();
TextField firstNameField = new TextField("First name");
binder.forField(firstNameField).bind(valueProvider, setter);

当您处理属于 bean 而不是 Property 的部分时,您有几个不同的选择。例如,人的“年龄”可以作为他们“出生年份”的函数来计算。假设我们只希望能够编辑出生年份,但我们还希望将年龄显示为只读值。它也可以是基于年龄或其他东西的折扣百分比。

第一种也是最简单的方法是使用 Field,但只有 ValueProvider 而没有 Setter。所以你可以有这样的东西(为简单起见使用 TextField):

Binder<Person> binder = new Binder<>();
TextField ageField = new TextField("Age (calculated)");
binder.forField(ageField).bind(person -> calculateAge(person.getBirthYear()), null);

这种方法的缺点是您仍在使用 TextField,它是一个编辑器组件。您可以将其设置为只读模式,这样用户就无法更改该值,但它仍然看起来您也许可以在某个时候对其进行编辑。

您可以使用的另一件事是 ReadOnlyHasValue,这是一个用于创建没有 SetterProperty 的界面。它有点笨拙,但您可以将其与绑定一起使用:

Span ageDisplay = new Span();
ReadOnlyHasValue<String> ageField = new ReadOnlyHasValue<>(text -> ageDisplay.setText(text));
binder.forField(ageField).bind(person -> calculateAge(person.getBirthYear()), null);

最后,由于 ValueProviderSetter 只是 Java 接口,您可以使用任何类型的副作用来实现它们。因此,您可以将任何逻辑搭载到 属性 的更改中:

Binder<Person> binder = new Binder<>();
Span ageDisplay = new Span();
TextField birthYear = new TextField();
binder.forField(birthYear)
  .bind(person -> { // ValueProvider
    return person.getBirthYear();
  }, (person, newBirthYear) -> { // Setter
    person.setBirthYear(newBirthYear);
    ageDisplay.setText(calculateAge(newBirthYear));
  });