Можно ли привязать непустое состояние ObservableList внутри ObjectProperty с помощью Bindings API?

У меня есть ситуация, когда я хочу связать BooleanProperty с непустым состоянием ObservableList, обернутым внутри ObjectProperty.

Вот основной синопсис поведения, которое я ищу:

    ObjectProperty<ObservableList<String>> obp = new SimpleObjectProperty<ObservableList<String>>();

    BooleanProperty hasStuff = new SimpleBooleanProperty();

    hasStuff.bind(/* What goes here?? */);

    // ObservableProperty has null value 
    assertFalse(hasStuff.getValue());

    obp.set(FXCollections.<String>observableArrayList());

    // ObservableProperty is no longer null, but the list has not contents.
    assertFalse(hasStuff.getValue());

    obp.get().add("Thing");

    // List now has something in it, so hasStuff should be true
    assertTrue(hasStuff.getValue());

    obp.get().clear();

    // List is now empty.
    assertFalse(hasStuff.getValue());

Я хотел бы использовать строителей в классе Bindings, а не реализовывать цепочку пользовательских привязок.

Теоретически метод Bindings.select(...) делает то, что я хочу, за исключением того, что Bindings.selectObservableCollection(...) нет, а преобразование возвращаемого значения из универсального select(...) и передача его в Bindings.isEmpty(...) не работает. То есть результат этого:

    hasStuff.bind(Bindings.isEmpty((ObservableList<String>) Bindings.select(obp, "value")));

вызывает ClassCastException:

java.lang.ClassCastException: com.sun.javafx.binding.SelectBinding$AsObject cannot be cast to javafx.collections.ObservableList

Возможен ли этот вариант использования только с Bindings API?


Решение

Основываясь на ответе @fabian, вот решение, которое сработало:

    ObjectProperty<ObservableList<String>> obp = new SimpleObjectProperty<ObservableList<String>>();

    ListProperty<String> lstProp = new SimpleListProperty<>();
    lstProp.bind(obp);

    BooleanProperty hasStuff = new SimpleBooleanProperty();
    hasStuff.bind(not(lstProp.emptyProperty()));

    assertFalse(hasStuff.getValue());

    obp.set(FXCollections.<String>observableArrayList());

    assertFalse(hasStuff.getValue());

    obp.get().add("Thing");

    assertTrue(hasStuff.getValue());

    obp.get().clear();

    assertFalse(hasStuff.getValue());

person metasim    schedule 06.02.2014    source источник
comment
В вашем решении зачем создавать ObjectProperty и ListProperty и почему бы не создать только ListProperty с вашим списком?   -  person dchang    schedule 02.12.2017


Ответы (3)


Я не вижу способа сделать это, используя только Bindings API. ObservableList не имеет пустого свойства, поэтому вы не можете использовать

Bindings.select(obp, "empty").isEqualTo(true)

а также

ObjectBinding<ObservableList<String>> lstBinding = Bindings.select(obp);
hasStuff.bind(lstBinding.isNotNull().and(lstBinding.isNotEqualTo(Collections.EMPTY_LIST)));

не работает, поскольку он обновляется только при изменении списка, но не при изменении его содержимого (т.е. третье утверждение не выполняется).

Но пользовательская цепочка привязок, которую вы должны создать, очень проста:

SimpleListProperty lstProp = new SimpleListProperty();
lstProp.bind(obp);
hasStuff.bind(lstProp.emptyProperty());
person fabian    schedule 07.02.2014
comment
Идеальный! Указание на SimpleListProperty было ключом .... Я обнаружил, что навигация по глубокой иерархии типов «Наблюдаемые», «Выражения», «Значения», «Свойства» и т. д. временами затруднена, поэтому определение точного импеданса matcher не всегда мне понятен. Рад видеть, что это так просто, когда вы знаете, как на это смотреть. - person metasim; 07.02.2014

Это можно было бы сделать с меньшим количеством переменных:

SimpleListProperty<String> listProperty = new SimpleListProperty<>(myObservableList);

BooleanProperty hasStuff = new SimpleBooleanProperty();
hasStuff.bind(not(listProperty.emptyProperty()));
person Sébastien B.    schedule 10.11.2016

Это действительно должно быть ObjectProperty<ObservableList<String>>? Если да, то этот ответ не решит вашу проблему...

Но я думаю, что если вы измените тип obp следующим образом:

Property<ObservableList<String>> obp = new SimpleListProperty<>();

Вы должны уметь использовать:

hasStuff.bind(Bindings.isEmpty((ListProperty<String>) obp));
person Harald K    schedule 07.02.2014
comment
К сожалению, это должно быть ObjectProperty<ObservableList<String>>, так как за моим вопросом я пытаюсь что-то связать с javafx.scene.chart.XYChart.dataProperty без раскрытия некоторых других базовых свойств приложения. - person metasim; 07.02.2014