Ответ 1
Кажется, это не то, что можно сделать более элегантно в JavaFX. Связывание и развязка кажется самым чистым способом.
Я сделал один способ сделать это сам. Не уверен, что в конечном итоге я его воспользуюсь (поскольку он просто заменяет дублирование кода с трудночитаемым кодом). Но это работает, и это ответ на мой собственный вопрос, поэтому я добавил его здесь.
Новый класс PersonEditor:
public class PersonEditor implements Initializable {
private SelectedObjectPropertyBinder<Person> selectedObjectPropertyBinder =
new SelectedObjectPropertyBinder<Person>();
@FXML private TextField nameField;
@FXML private TextField ageField;
@FXML private TextField heightField;
@Override
public void initialize(URL url, ResourceBundle rb) {
selectedObjectPropertyBinder.getBinders().add(
new ObjectPropertyBindHelper<Person>(nameField.textProperty()) {
@Override public Property objectProperty(Person p)
{ return p.nameProperty(); }
});
selectedObjectPropertyBinder.getBinders().add(
new ObjectPropertyBindHelper<Person>(ageField.textProperty()) {
@Override public Property objectProperty(Person p)
{ return p.ageProperty(); }
});
selectedObjectPropertyBinder.getBinders().add(
new ObjectPropertyBindHelper<Person>(heightField.textProperty()) {
@Override public Property objectProperty(Person p)
{ return p.heightProperty(); }
});
}
public void setSelection(ObjectProperty<Person> selectedPersonProperty) {
selectedObjectPropertyBinder.
setSelectedObjectProperty(selectedPersonProperty);
}
}
Вспомогательные классы:
public class SelectedObjectPropertyBinder<T> implements ChangeListener<T> {
private List<ObjectPropertyBindHelper<T>> binders =
new ArrayList<ObjectPropertyBindHelper<T>>();
public void setSelectedObjectProperty(Property<T> selectionProperty) {
selectionProperty.addListener(this);
}
public List<ObjectPropertyBindHelper<T>> getBinders() {
return binders;
}
@Override
public void changed(ObservableValue<? extends T> observable,
T oldVal, T newVal) {
if (oldVal != null)
for (ObjectPropertyBindHelper b : binders)
b.unbindBi(oldVal);
if (newVal != null)
for (ObjectPropertyBindHelper b : binders)
b.bindBi(newVal);
}
}
public abstract class ObjectPropertyBindHelper<T> {
private Property boundProperty;
public ObjectPropertyBindHelper(Property boundProperty) {
this.boundProperty = boundProperty;
}
public void bindBi(T o) {
boundProperty.bindBidirectional(objectProperty(o));
}
public void unbindBi(T o) {
boundProperty.unbindBidirectional(objectProperty(o));
}
public abstract Property objectProperty(T t);
public Property getBoundProperty() {
return boundProperty;
}
}
Как сказал Скоттб в своем ответе, связующая ссылка это не всегда то, что вы хотите в любом случае. Если вы хотите иметь возможность отменять/фиксировать изменения, вы можете реализовать это, используя также подобное (но, вероятно, будет еще труднее прочитать полученный код).