As James_D say, this functionality is absent in standard API and the one can use ReactFX framework for doing so. But if the excess dependents is not the option, such functionality can be easy implemented without them. For this it is enough to go throught the JDK sources of Bindings#bindContent
to ContentBinding#bind
to ListContentBinding
class and copy/paste with the neccessary modifications. As a result we get a binding which work like standard content binding:
ObservableList<Model> models = FXCollections.observableArrayList();
ObservableList<TreeItem<Model>> treeItemModels = FXCollections.observableArrayList();
BindingUtil.mapContent(treeItemModels, models, m -> new TreeItem<Model>(m));
The sources of this BindingUtil
:
public class BindingUtil {
public static <E, F> void mapContent(ObservableList<F> mapped, ObservableList<? extends E> source,
Function<? super E, ? extends F> mapper) {
map(mapped, source, mapper);
}
private static <E, F> Object map(ObservableList<F> mapped, ObservableList<? extends E> source,
Function<? super E, ? extends F> mapper) {
final ListContentMapping<E, F> contentMapping = new ListContentMapping<E, F>(mapped, mapper);
mapped.setAll(source.stream().map(mapper).collect(toList()));
source.removeListener(contentMapping);
source.addListener(contentMapping);
return contentMapping;
}
private static class ListContentMapping<E, F> implements ListChangeListener<E>, WeakListener {
private final WeakReference<List<F>> mappedRef;
private final Function<? super E, ? extends F> mapper;
public ListContentMapping(List<F> mapped, Function<? super E, ? extends F> mapper) {
this.mappedRef = new WeakReference<List<F>>(mapped);
this.mapper = mapper;
}
@Override
public void onChanged(Change<? extends E> change) {
final List<F> mapped = mappedRef.get();
if (mapped == null) {
change.getList().removeListener(this);
} else {
while (change.next()) {
if (change.wasPermutated()) {
mapped.subList(change.getFrom(), change.getTo()).clear();
mapped.addAll(change.getFrom(), change.getList().subList(change.getFrom(), change.getTo())
.stream().map(mapper).collect(toList()));
} else {
if (change.wasRemoved()) {
mapped.subList(change.getFrom(), change.getFrom() + change.getRemovedSize()).clear();
}
if (change.wasAdded()) {
mapped.addAll(change.getFrom(), change.getAddedSubList()
.stream().map(mapper).collect(toList()));
}
}
}
}
}
@Override
public boolean wasGarbageCollected() {
return mappedRef.get() == null;
}
@Override
public int hashCode() {
final List<F> list = mappedRef.get();
return (list == null) ? 0 : list.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
final List<F> mapped1 = mappedRef.get();
if (mapped1 == null) {
return false;
}
if (obj instanceof ListContentMapping) {
final ListContentMapping<?, ?> other = (ListContentMapping<?, ?>) obj;
final List<?> mapped2 = other.mappedRef.get();
return mapped1 == mapped2;
}
return false;
}
}
}
toList()
toCollectors.toList()
to make it compile. – Fair